void yuv2rgb(uint8_t * yuvDat,uint8_t * out,int alg,uint32_t img_w,uint32_t img_h){ uint32_t xy; int y1,y2,y3,y4; switch(alg){ case ALG_YUV_0: y1=0; y2=2; y3=1; y4=3; break; case ALG_YUV_1: y1=2; y2=0; y3=1; y4=3; break; case ALG_YUV_2: y1=0; y2=2; y3=3; y4=1; break; case ALG_YUV_3: y1=2; y2=0; y3=3; y4=1; break; } for (xy=0;xy<(img_w/2)*img_h;++xy){ *out++=YUV2R(yuvDat[y1],yuvDat[y3],yuvDat[y4]); *out++=YUV2G(yuvDat[y1],yuvDat[y3],yuvDat[y4]); *out++=YUV2B(yuvDat[y1],yuvDat[y3],yuvDat[y4]); *out++=YUV2R(yuvDat[y2],yuvDat[y3],yuvDat[y4]); *out++=YUV2G(yuvDat[y2],yuvDat[y3],yuvDat[y4]); *out++=YUV2B(yuvDat[y2],yuvDat[y3],yuvDat[y4]); yuvDat+=4; } }
/* Computes the pixel value after adjusting the white balance to the current * one. The input the y, u, v channel of the pixel and the adjusted value will * be stored in place. The adjustment is done in RGB space. */ void EmulatedCameraDevice::changeWhiteBalance(uint8_t& y, uint8_t& u, uint8_t& v) const { float r_scale = mWhiteBalanceScale[0]; float b_scale = mWhiteBalanceScale[2]; int r = static_cast<float>(YUV2R(y, u, v)) / r_scale; int g = YUV2G(y, u, v); int b = static_cast<float>(YUV2B(y, u, v)) / b_scale; y = RGB2Y(r, g, b); u = RGB2U(r, g, b); v = RGB2V(r, g, b); }
static void reduceImage(uint8_t * image,uint8_t * found_colors,int row,unsigned offsetPal,Fl_Progress *progress,Fl_Window*pwin,unsigned maxCol,unsigned yuv,unsigned alg,bool isSprite=false,bool ditherBefore=true){ if(progress) progress->maximum(1.0); unsigned off2=offsetPal*2; unsigned off3=offsetPal*3; unsigned colors_found; unsigned w,h; unsigned maxPal=maxCol; unsigned msprt=curSpritemeta; if(isSprite){ w=currentProject->ms->sps[msprt].width(curSpritegroup); h=currentProject->ms->sps[msprt].height(curSpritegroup); currentProject->ms->sps[msprt].spriteGroupToImage(image,curSpritegroup,row,false); }else{ w=currentProject->tms->maps[currentProject->curPlane].mapSizeW; h=currentProject->tms->maps[currentProject->curPlane].mapSizeHA; w*=currentProject->tileC->sizew; h*=currentProject->tileC->sizeh; currentProject->tms->maps[currentProject->curPlane].truecolor_to_image(image,row,false); } if(progress){ progress->label("Dithering to colorspace"); Fl::check(); } if((!yuv)&&ditherBefore) ditherImage(image,w,h,false,true); if(progress){ progress->label("Quantizing image"); Fl::check(); } colors_found=count_colors(image,w,h,&found_colors[0],false); printf("Unique colors %d\n",colors_found); if (colors_found <= maxCol){ printf("%d colors\n",colors_found); unsigned offsetTmp=offsetPal; for (unsigned x=0;x<colors_found;x++){ uint_fast8_t r,g,b; againFun: if (currentProject->pal->palType[offsetTmp]){ ++offsetTmp; if(offsetTmp>=maxPal) goto actullyNeededReduction; goto againFun; } r=found_colors[(x*3)]; g=found_colors[(x*3)+1]; b=found_colors[(x*3)+2]; printf("R=%d G=%d B=%d\n",r,g,b); if(currentProject->pal->shouldAddCol(offsetTmp,r,g,b,isSprite)){ currentProject->pal->rgbToEntry(r,g,b,offsetTmp); currentProject->pal->updateRGBindex(offsetTmp); ++offsetTmp; } } if(currentProject->gameSystem==NES) updateEmphesis(); if(window) window->redraw(); }else{ actullyNeededReduction: printf("More than %d colors reducing to %d colors\n",maxCol,maxCol); uint8_t user_pal[3][256]; uint8_t rgb_pal2[768]; uint8_t rgb_pal3[768]; unsigned colorz=maxCol; bool can_go_again=true; uint8_t*imageuse; uint8_t*output; if(alg==1) output=(uint8_t*)malloc(w*h*3); if(yuv){ imageuse=(uint8_t*)malloc(w*h*3); uint32_t x,y; uint8_t*imageptr=image; uint8_t*outptr=imageuse; for(y=0;y<h;y++){ for(x=0;x<w;x++){ if(yuv==2){ outptr[0]=CRGB2Y(imageptr[0],imageptr[1],imageptr[2]); outptr[1]=CRGB2Cb(imageptr[0],imageptr[1],imageptr[2]); outptr[2]=CRGB2Cr(imageptr[0],imageptr[1],imageptr[2]); }else{ outptr[0]=RGB2Y(imageptr[0],imageptr[1],imageptr[2]); outptr[1]=RGB2U(imageptr[0],imageptr[1],imageptr[2]); outptr[2]=RGB2V(imageptr[0],imageptr[1],imageptr[2]); } imageptr+=3; outptr+=3; } } }else imageuse=image; try_again_color: switch(alg){ case 4: dl1quant(imageuse,w,h,colorz,user_pal); break; case 3: wu_quant(imageuse,w,h,colorz,user_pal); break; case 2: NEU_wrapper(w,h,imageuse,colorz,user_pal); break; case 1: scolorq_wrapper(imageuse,output,user_pal,w,h,colorz); break; default: dl3quant(imageuse,w,h,colorz,user_pal,true,progress);/*this uses denesis lee's v3 color quant which is found at http://www.gnu-darwin.org/www001/ports-1.5a-CURRENT/graphics/mtpaint/work/mtpaint-3.11/src/quantizer.c*/ } for (unsigned x=0;x<colorz;x++){ unsigned r,g,b; if(yuv){ if(yuv==2){ r=CYCbCr2R(user_pal[0][x],user_pal[1][x],user_pal[2][x]); g=CYCbCr2G(user_pal[0][x],user_pal[1][x],user_pal[2][x]); b=CYCbCr2B(user_pal[0][x],user_pal[1][x],user_pal[2][x]); }else{ r=YUV2R(user_pal[0][x],user_pal[1][x],user_pal[2][x]); g=YUV2G(user_pal[0][x],user_pal[1][x],user_pal[2][x]); b=YUV2B(user_pal[0][x],user_pal[1][x],user_pal[2][x]); } }else{ r=user_pal[0][x]; g=user_pal[1][x]; b=user_pal[2][x]; } switch(currentProject->gameSystem){ case segaGenesis: r=nearest_color_index(r); g=nearest_color_index(g); b=nearest_color_index(b); rgb_pal2[(x*3)]=palTab[r]; rgb_pal2[(x*3)+1]=palTab[g]; rgb_pal2[(x*3)+2]=palTab[b]; break; case NES: {uint8_t temp=currentProject->pal->to_nes_color_rgb(r,g,b); uint32_t temp_rgb = nesPalToRgb(temp); rgb_pal2[(x*3)]=(temp_rgb>>16)&255; rgb_pal2[(x*3)+1]=(temp_rgb>>8)&255; rgb_pal2[(x*3)+2]=temp_rgb&255;} break; case masterSystem: case gameGear: {const uint8_t*palUseTab=currentProject->gameSystem==gameGear?palTabGameGear:palTabMasterSystem; unsigned colsTab=currentProject->gameSystem==gameGear?16:4; r=nearestOneChannel(r,palUseTab,colsTab); g=nearestOneChannel(g,palUseTab,colsTab); b=nearestOneChannel(b,palUseTab,colsTab); rgb_pal2[(x*3)]=palUseTab[r]; rgb_pal2[(x*3)+1]=palUseTab[g]; rgb_pal2[(x*3)+2]=palUseTab[b];} break; default: show_default_error } } unsigned new_colors = count_colors(rgb_pal2,colorz,1,rgb_pal3); printf("Unique colors in palette %u\n",new_colors); if (new_colors < maxCol){ if (can_go_again == true){ if (colorz != 512) colorz++; else can_go_again=false; char tmp[1024]; snprintf(tmp,1024,"Found only %d colors trying again with %d",new_colors,colorz); tmp[sizeof(tmp)-1]=0; if(pwin){ pwin->copy_label(tmp); Fl::check(); } puts(tmp); goto try_again_color; } } if (new_colors > maxCol){ can_go_again=false; if(pwin) pwin->label("Too many colors"); colorz--; goto try_again_color; } unsigned offsetTmp=offsetPal; for (unsigned x=0;x<maxCol;x++){ againNerd: if (currentProject->pal->palType[offsetTmp]){ ++offsetTmp; if(offsetTmp>(maxPal+offsetPal)){ if(maxCol>1){ --colorz; printf("Needed to reduce colors generated due to locked colors %u\n",maxCol); }else{ fl_alert("Cannot reduce maximum colors to make this happen...aborting"); return; } goto try_again_color; } goto againNerd; } unsigned r=rgb_pal3[x*3],g=rgb_pal3[x*3+1],b=rgb_pal3[x*3+2]; if(currentProject->pal->shouldAddCol(offsetTmp,r,g,b,isSprite)){ memcpy(currentProject->pal->rgbPal+(offsetTmp*3),rgb_pal3+(x*3),3); currentProject->pal->rgbToEntry(r,g,b,offsetTmp); ++offsetTmp; } } if(currentProject->gameSystem==NES) updateEmphesis(); if(alg==1){ if(isSprite) currentProject->ms->sps[msprt].spriteImageToTiles(output,curSpritegroup,row,false); else currentProject->tms->maps[currentProject->curPlane].truecolorimageToTiles(output,row,false); free(output); } if(yuv) free(imageuse); } }
void I3C_Converter::YUV2Pixel(YUV *yuv, Pixel *pixel) { pixel->red = YUV2R(yuv->Y, yuv->U, yuv->V); pixel->green = YUV2G(yuv->Y, yuv->U, yuv->V); pixel->blue = YUV2B(yuv->Y, yuv->U, yuv->V); }