YUV⇔RGB変換での問題について

このQ&Aのポイント
  • YUV⇔RGB変換がうまくいかない問題について解決方法を教えてください。
  • 24bppRaw(R,G,Bの順番)をYUVに変換する式とYUVをRGBのrawに変換する式を使用していますが、画像がおかしくなる問題が発生しています。
  • 元のRGBに戻る方法や、正しい変換式について教えてください。
回答を見る
  • ベストアンサー

YUV⇔RGB変換がうまくいきません。

24bppRaw(R,G,Bの順番)を以下の式でYUVに変換します。 layer[i+j]がRでlayer[i+j+1]がGでlayer[i+j+2]がBです。 Y=(unsigned char)(0.257*layer[i+j]+0.504*layer[i+j+1]+0.098*layer[i+j+2]+16); U=(unsigned char)(-0.148*layer[i+j]-0.291*layer[i+j+1]+0.439*layer[i+j+2]+128); V=(unsigned char)(0.439*layer[i+j]-0.368*layer[i+j+1]-0.071*layer[i+j+2]+128); そのあとにYUVをRGBのrawに以下の式で変換します。 Y=layer[i+j]; U=layer[i+j+1]-128; V=layer[i+j+2]-128; R=(unsigned char)(1.164*(Y-16)+1.596*V); B=(unsigned char)(1.164*(Y-16)+2.018*U); G=(unsigned char)(1.164*(Y-16)-0.391*U-0.813*V); しかし元のRGBにはならず画像がおかしくなります。 もちろんオーバーフロー、アンダーフローなどは丸めています。 どのような式を用いれば、RGB⇔YUV 相互変換ができるのが ご教授ください。もう半年くらい随分迷っています。 ダイレクトに式だけ提示いただけるだけで結構なので よろしくおねがいいたしますm(___)m 参考HP http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html http://www.sm.rim.or.jp/~shishido/yuv.html

質問者が選んだベストアンサー

  • ベストアンサー
  • jgk
  • ベストアンサー率75% (104/138)
回答No.1

式はソースからそのまま抜き出してきたものでしょうか? もしそうなら、まずオーバーフローの処理がまずいです。 計算結果がunsigned charの範囲外になる場合があって、unsigned charの範囲内に丸めるためには、 計算結果を取りうる範囲の変数(例えばint)に入れて、丸めの処理をしたあと、 unsigned charに代入する必要があります。 RGB→YUVの時、U,Vはunsigned charだったりしませんか? unsigned charのU,Vに-128を引いた値を入れてしまうと、 layer[i+j+1]、layer[i+j+2]が128以下のときオーバーフローが発生してしまいます。 ですので、U,Vをint等にするか、 Yと同じように式中で- 128してあげる必要があります。 (これは型を指定してない整数リテラルがint型なのと、 暗黙の型変換によってintに昇格されて計算されるため、 オーバーフローが発生しなくなっています) サンプルコードです。 layerはunsigned charと仮定します。 丸め範囲はYUV,RGBともに0~255にしています。 RGB→YUV Yo, Uo, Voが出力です。 int Ys, Us, Vs; unsigned char Yo, Uo, Vo; Ys = 0.257 * layer[i+j] + 0.504 * layer[i+j+1] + 0.098 * layer[i+j+2] + 16; Us = -0.148 * layer[i+j] - 0.291 * layer[i+j+1] + 0.439 * layer[i+j+2] + 128; Vs = 0.439 * layer[i+j] - 0.368 * layer[i+j+1] - 0.071 * layer[i+j+2] + 128; if( Ys < 0 ){ Yo = 0; }else if( Ys > 255 ){ Yo = 255; }else{ Yo = Ys; } if( Us < 0 ){ Uo = 0; }else if( Us > 255 ){ Uo = 255; }else{ Uo = Us; } if( Vs < 0 ){ Vo = 0; }else if( Vs > 255 ){ Vo = 255; }else{ Vo = Vs; } YUV→RGB Ro, Go, Boが出力です。 int Y, U, V; int Rs, Gs, Bs; unsigned char Ro, Go, Bo; Y = layer[i+j] - 16; U = layer[i+j+1] - 128; V = layer[i+j+2] - 128; Rs = 1.164 * Y + 1.596 * V; Bs = 1.164 * Y + 2.018 * U; Gs = 1.164 * Y - 0.391 * U - 0.813 * V; if( Rs < 0 ){ Ro = 0; }else if( Rs > 255 ){ Ro = 255; }else{ Ro = Rs; } if( Gs < 0 ){ Go = 0; }else if( Gs > 255 ){ Go = 255; }else{ Go = Gs; } if( Bs < 0 ){ Bo = 0; }else if( Bs > 255 ){ Bo = 255; }else{ Bo = Bs; }

ringist
質問者

お礼

こんばんは! ご指摘通りunsigned charにしておりました intにして計算したところ 変換がうまくいきました。。。ご指摘鋭かったです 本当にありがとうございました!!

関連するQ&A

  • RGB→YUV変換のプログラム

    RGB→YUV変換を行っているのですが、 うまくいきません。 以下であっているのでしょうか? //RGB > YUV変換 void RGBtoYUV(char *filename,int width,int height) { FILE *fpt,*fpt_output; unsigned char *Input,*head; unsigned char Y=0,U=0,V=0; int i,j,b_flag=1; int modification=0; modification=width%4; //ファイルのオープン fopen_s(&fpt,filename,"rb"); if(fpt==NULL) { char DebugStr[256]; wsprintf(DebugStr,"%sが存在しません",filename); MessageBox(NULL,DebugStr,"File Error",MB_OK); } else { fopen_s(&fpt_output,"YUV.bmp","wb"); //ヘッダ情報の書き込み head=(unsigned char*)malloc(54); fread(head,sizeof(unsigned char),54,fpt); fwrite(head,sizeof(unsigned char),54,fpt_output); free(head); Input=(unsigned char*)malloc(3*width*height*sizeof(unsigned char)); //メモリに展開 for(i=0;i<height;i++) { fread(&Input[i*(3*width)],sizeof(unsigned char),3*width,fpt); fseek(fpt,modification,SEEK_CUR); } fclose(fpt);//Inputファイルのクローズ for(i=0;i<3*width*height;i+=3*width) { for(j=0;j<3*width;j+=3) { Y=(unsigned char)(0.299*Input[i+j+2]+0.587*Input[i+j+1]+0.114*Input[i+j]); U=(unsigned char)(-0.169*Input[i+j+2]-0.3316*Input[i+j+1]+0.500*Input[i+j]); V=(unsigned char)(0.500*Input[i+j+2]-0.4186*Input[i+j+1]-0.0813*Input[i+j]); //Y if(Y<0) { Input[i+j]=0x00; } else if(Y>255) { Input[i+j]=0xff; } else { Input[i+j]=Y; } //U if(U<0) { Input[i+j+1]=0x00; } else if(U>255) { Input[i+j+1]=0xff; } else { Input[i+j+1]=U; } //V if(V<0) { Input[i+j+2]=0x00; } else if(V>255) { Input[i+j+2]=0xff; } else { Input[i+j+2]=V; } } }//i fseek(fpt_output,54,SEEK_SET); for(i=0;i<height;i++) { fwrite(&Input[3*width*i],sizeof(unsigned char),3*width,fpt_output); //修正値の代入 for(j=0;j<modification;j++) { fwrite("\x000",sizeof(unsigned char),1,fpt_output); } } fclose(fpt_output); free(Input); } } 又 YUV→RGBにすると元の画像に戻らずに困っています。 プログラムに対するご指摘お願いします。 このプログラムはWindowGUIで幅と高さとファイル名を入力して 走らせるプログラムです。24bpp BMPが対象です。

  • RGBをCMYKに変換するプログラム

    Windows7 VS2008 SP1 RGBからCMYKに変換するプログラムを以下の様に書いている ([詳解]画像処理プログラミング という本に載っている ソースです) のですがうまくいきません。 おそらく型の扱い??だと思うのですが・・ 具体的にどの部分を修正すればいいのかご指摘お願いします。 INPUT:24bpp raw int RawToCMYK(WCHAR *filename,int width,int height) { FILE *fpt; FILE *fpt_C,*fpt_M,*fpt_Y,*fpt_K; unsigned char *layer; unsigned char *C,*M,*Y,*K; int i,j; _wfopen_s(&fpt,filename,L"rb"); if(fpt==0x00) { MessageBox(NULL,L"RawToCMYK Error",L"RawToCMYK Error",MB_OK); return -1; } else { layer=(unsigned char*)malloc(3*width*height); C=(unsigned char *)malloc(width*height); M=(unsigned char *)malloc(width*height); Y=(unsigned char *)malloc(width*height); K=(unsigned char *)malloc(width*height); fread(&layer[0],sizeof(unsigned char),3*width*height,fpt); fclose(fpt); _wfopen_s(&fpt_C,L"RawToC.raw",L"wb"); _wfopen_s(&fpt_M,L"RawToM.raw",L"wb"); _wfopen_s(&fpt_Y,L"RawToY.raw",L"wb"); _wfopen_s(&fpt_K,L"RawToK.raw",L"wb"); for(i=0;i<3*width*height;i+=3*width) { for(j=0;j<3*width;j+=3) { C[i/3+j/3]=255-layer[i+j]; M[i/3+j/3]=255-layer[i+j+1]; Y[i/3+j/3]=255-layer[i+j+2]; K[i/3+j/3]=min3(C[i/3+j/3],M[i/3+j/3],Y[i/3+j/3]); if(K[i/3+j/3]==0xff) { C[i/3+j/3]=0x00; M[i/3+j/3]=0x00; Y[i/3+j/3]=0x00; } else { C[i/3+j/3]=(C[i/3+j/3]-K[i/3+j/3])*255/(255-K[i/3+j/3]); M[i/3+j/3]=(M[i/3+j/3]-K[i/3+j/3])*255/(255-K[i/3+j/3]); Y[i/3+j/3]=(Y[i/3+j/3]-K[i/3+j/3])*255/(255-K[i/3+j/3]); } } } fwrite(&C[0],sizeof(unsigned char),width*height,fpt_C); fwrite(&M[0],sizeof(unsigned char),width*height,fpt_M); fwrite(&Y[0],sizeof(unsigned char),width*height,fpt_Y); fwrite(&K[0],sizeof(unsigned char),width*height,fpt_K); fclose(fpt_C); fclose(fpt_M); fclose(fpt_Y); fclose(fpt_K); free(C); free(M); free(Y); free(K); return 0;

  • カラー画像からグレースケール画像フォーマットの変換

    カラー画像からグレースケール画像フォーマットの変換するプログラムなんですが、いまいち理解できていません。 プログラムはRGB構造体を使ってのものなんですが添削お願いいたします。 #include<stdio.h> #include<stdlib.h> typedef struct _RGB { unsigned char r; unsigned char g; unsigned char b; } RGB; int main(int argc, char *argv[]) { int x, y; unsigned char *in, *out; int i, j, Magic, level; unsigned char tmp[255]; RGB **pixels; int width = 255; int height = 255; int size = width * height; FILE *fin, *fout; if(argc != 3){ printf("Usage : %s input outpu \n", argv[0]); exit(1); } fin = fopen(argv[1], "rb"); fgets(tmp, 255, fin); if(tmp[0] != 'P'){ return 0; } sscanf(tmp, "P%d", &Magic); if(Magic < 1 || Magic > 6){ return 0; } do{ fgets(tmp, 255, fin); } while(tmp[0] == '#'); sscanf(tmp, "%d %d", &x, &y); if(x < 1 || y < 1){ return 0; } fgets(tmp, 255, fin); sscanf(tmp, "%d", &level); printf("P%d\n", &Magic); printf("%d %d\n", x, y); printf("%d\n", level); in = (unsigned char *)malloc(sizeof(unsigned char) *x*y); fread(in, sizeof(unsigned char), x*y, fin); pixels = (RGB**)malloc(width*sizeof(RGB*)); pixels[0] = (RGB* )malloc(size * sizeof(RGB)); for(i = 1; i < width; i++){ pixels[i] = pixels[i - 1] + height; } free(pixels[0]); for(i = 1; i < width * height * 3; i++){ out[i] = pixels[i][0].r * 0.299 + pixels[i][1].g * 0.587 + pixels[i][2].b * 0.114; } fout = fopen(argv[2], "wb"); fprintf(fout,"P%d\n",Magic); fprintf(fout,"# My new PGM\n"); fprintf(fout,"%d %d\n",x, y); fprintf(fout,"%d\n",level); fwrite(out, sizeof(unsigned char),x*y, fout); free(pixels); free(in); free(out); free(fin); free(fout); }

  • YUV動画像を1ピクセルごとにずらしていく方法がわかりません・・・

    動画像を1フレーム毎に1ピクセルずつ右にずらし右にはみでたピクセルは左の欠けた部分にそのまま補完するプログラムを作りたいのですが途中からわかりません;; ピクセルどどうやって右のやつを左にもっていくのかがさっぱりで・・・どなたかお願いします。 #include <stdio.h> #include <stdlib.h> #define x_size 352 #define y_size 288 #define FN 200 typedef struct { unsigned char Y[x_size*y_size]; unsigned char U[x_size*y_size/4]; unsigned char V[x_size*y_size/4]; } FRAME; int main(void) { FILE *fpr; FILE *fpw; char file_name1[100]="zikken2.yuv"; char file_name2[100]="./out.yuv"; int i, frame_num,j; FRAME *ref; if((fpr = fopen(file_name1, "rb")) == NULL){ fprintf(stderr, "Can't open %s in read mode\n", file_name1); exit(-1); } if((fpw = fopen(file_name2, "wb")) == NULL){ fprintf(stderr, "Can't open %s in write mode\n", file_name2); exit(-1); } ref = (FRAME *)malloc(sizeof(FRAME)); /* read from file */ for(frame_num=0; frame_num<FN; frame_num++){ for(i = 0; i<x_size*y_size; i++){ ref->Y[i] = getc(fpr); } for(i = 0; i<x_size*y_size/4; i++){ ref->U[i] = getc(fpr); } for(i = 0; i<x_size*y_size/4; i++){ ref->V[i] = getc(fpr); } /* write to file */ fwrite(ref,1,sizeof(FRAME),fpw); } fclose(fpr); fclose(fpw); free(ref); return 0; }

  • RGBからYUVへの変換(Matlab)についての質問です.

    先ほども質問させていただきましたが, 画像に誤りがあった為再度投稿させていただきます. 貴重なスペースを無駄に使用してしまい大変申し訳ありません. >> 現在Matlabを勉強中の者です. 160*120ピクセルの画像の色空間を RGBからYUV(YCbCr)へ変換するプログラムを考えているのですが, 以下のソースコードで大まかな点はあっているでしょうか? 実際にYUVへ変換後,画像を表示したところ, 元画像とは色調が変わってしまい頭を抱えています. 画像を表示する際のカラーマップに問題があるのでしょうか. ご教授お願い致します. % 画像ファイルの読込 pictureRgb = imread('./data/gazou0.bmp'); pictureYcbcr = imread('./data/gazou0.bmp'); % YCbCr空間(フルレンジ)への変換 pictureYcbcr(:,:,1) = uint8(0.257 * double(pictureRgb(:,:,1)) + 0.504 * double(pictureRgb(:,:,2))... + 0.098 * double(pictureRgb(:,:,3))+16.0); pictureYcbcr(:,:,2) = uint8(-0.148 * double(pictureRgb(:,:,1)) - 0.291 * double(pictureRgb(:,:,2))... + 0.439 * double(pictureRgb(:,:,3))+128.0); pictureYcbcr(:,:,3) = uint8(0.439 * double(pictureRgb(:,:,1)) - 0.368 * double(pictureRgb(:,:,2))... + 0.071 * double(pictureRgb(:,:,3))+128.0); %R成分の表示 subplot(3,3,1); image(pictureRgb(:,:,1)); axis image; axis off; title('R 成分'); %G成分の表示 subplot(3,3,2); image(pictureRgb(:,:,2)); axis image; axis off; title('G 成分'); %B成分の表示 subplot(3,3,3); image(pictureRgb(:,:,3)); axis image; axis off; title('B 成分'); %--------------------------- %Y成分の表示 subplot(3,3,4); image(pictureYcbcr(:,:,1)); axis image; axis off; title('Y 成分'); %Cb成分の表示 subplot(3,3,5); image(pictureYcbcr(:,:,2)); axis image; axis off; title('Cb成分'); %Cr成分の表示 subplot(3,3,6); image(pictureYcbcr(:,:,3)); axis image; axis off; title('Cr成分'); %--------------------------- %原画像の表示 subplot(3,3,7); image(pictureRgb); axis image; axis off; title('元画像'); %YUV画像の表示 subplot(3,3,8); image(pictureYcbcr); axis image; axis off; title('YUV画像');

  • RGB値からHSV値への変換式に関して質問があります.

    RGB値からHSV値への変換式に関して質問があります. S=MAX[R,G,B]-MIN[R,G,B] V=MAX[R,G,B] の2式は分光分布を見れば,その式の意味は理解できました. ただ, H=60*(G-B)/(MAX[R,G,B]-MIN[R,G,B]) if R=MAX[R,G,B] H=60*(B-R)/(MAX[R,G,B]-MIN[R,G,B])+120 if G=MAX[R,G,B] H=60*(R-G)/(MAX[R,G,B]-MIN[R,G,B])+240 if B=MAX[R,G,B] の式の意味が理解できません. なぜ,最大値でない残りの2値の差を彩度で割ると色相が算出されるのでしょうか. どなたか分かる方,回答よろしくお願い致します.

  • MatlabによるRGB空間からYUV空間への変更について.

    現在Matlabを勉強中の者です. 160*120ピクセルの画像の色空間を RGBからYUV(YCbCr)へ変換するプログラムを考えているのですが, 以下のソースコードで大まかな点はあっているでしょうか? 実際にYUVへ変換後,画像を表示したところ, 元画像とは色調が変わってしまい頭を抱えています. 画像を表示する際のカラーマップに問題があるのでしょうか. ご教授お願い致します. % 画像ファイルの読込 pictureRgb = imread('./data/gazou0.bmp'); pictureYcbcr = imread('./data/gazou0.bmp'); % YCbCr空間(フルレンジ)への変換 pictureYcbcr(:,:,1) = uint8(0.257 * double(pictureRgb(:,:,1)) + 0.504 * double(pictureRgb(:,:,2))... + 0.098 * double(pictureRgb(:,:,3))+16.0); pictureYcbcr(:,:,2) = uint8(-0.148 * double(pictureRgb(:,:,1)) - 0.291 * double(pictureRgb(:,:,2))... + 0.439 * double(pictureRgb(:,:,3))+128.0); pictureYcbcr(:,:,3) = uint8(0.439 * double(pictureRgb(:,:,1)) - 0.368 * double(pictureRgb(:,:,2))... + 0.071 * double(pictureRgb(:,:,3))+128.0); %R成分の表示 subplot(3,3,1); image(pictureRgb(:,:,1)); axis image; axis off; title('R 成分'); %G成分の表示 subplot(3,3,2); image(pictureRgb(:,:,2)); axis image; axis off; title('G 成分'); %B成分の表示 subplot(3,3,3); image(pictureRgb(:,:,3)); axis image; axis off; title('B 成分'); %--------------------------- %Y成分の表示 subplot(3,3,4); image(pictureYcbcr(:,:,1)); axis image; axis off; title('Y 成分'); %Cb成分の表示 subplot(3,3,5); image(pictureYcbcr(:,:,2)); axis image; axis off; title('Cb成分'); %Cr成分の表示 subplot(3,3,6); image(pictureYcbcr(:,:,3)); axis image; axis off; title('Cr成分'); %--------------------------- %原画像の表示 subplot(3,3,7); image(pictureRgb); axis image; axis off; title('元画像'); %YUV画像の表示 subplot(3,3,8); image(pictureYcbcr); axis image; axis off; title('YUV画像');

  • 座標変換について

    座標変換について 回転座標変換を表す行列を R=(R_ij) と書く事にします。 v_i'=Σ【j=1→3】R_ijv_j のように変換されるものとします。 ここで、 (1) 『座標変換で矢印(ベクトル)そのものは変わらないから、内積は回転しても変わらない』 とはどういうことですか? (2)『そこで、任意のベクトル↑u,↑vに対して Σ【i=1→3】u_i'v_i'=Σ【i,j,k=1→3】R_ijR_iku_jv_k=Σ【i=1→3】u_iv_i が成り立たなければならない。このためには Σ【i=1→3】R_ijR_ik=δ_jk となっていることが必要十分である。』 などと書いてありましたが、この理由がわかりません。

  • 1bppファイルを8bpp(raw)に変換する。

    環境 Windows7 VS2008 SP1 1bppの画像を8bppに変換しようとしているのですが うまくいきません。自分ではこれで 合っていると思うのですが・・・ 何かアドバイスお願いしますm(__)m int Main1bppTo8bpp(WCHAR *filename,int width,int height) { //width,heightは8bppになったときの幅,高さを指定する。 FILE *fpt; _wfopen_s(&fpt,filename,L"rb"); if(fpt==0x00) { MessageBox(NULL,L"1bppTo8bpp Error",L"1bppTo8bpp Error",MB_OK); return -1; } else { unsigned char *layer,*Output; layer=(unsigned char*)calloc(((width/8)+1)*height*sizeof(unsigned char),sizeof(unsigned char)); Output=(unsigned char*)malloc(width*height); //読み込み fread(&layer[0],sizeof(unsigned char),((width/8)+1)*height,fpt); FILE *fpt_output; _wfopen_s(&fpt_output,L"1bppTo8bpp.raw",L"wb"); int i,j,flag=0x00; for(i=0;i<((width/8)+1)*height;i+=((width/8)+1)) { for(j=0;j<((width/8)+1);j++) { //8bit目 if((layer[i+j]&BIT8)==BIT8) { Output[i+j+flag]=0x00; } else { Output[i+j+flag]=0xff; } //7bit目 if((layer[i+j]&BIT7)==BIT7) { Output[i+j+flag+1]=0x00; } else { Output[i+j+flag+1]=0xff; } //6bit目 if((layer[i+j]&BIT6)==BIT6) { Output[i+j+flag+2]=0x00; } else { Output[i+j+flag+2]=0xff; } //5bit目 if((layer[i+j]&BIT5)==BIT5) { Output[i+j+flag+3]=0x00; } else { Output[i+j+flag+3]=0xff; } //4bit目 if((layer[i+j]&BIT4)==BIT4) { Output[i+j+flag+4]=0x00; } else { Output[i+j+flag+4]=0xff; } //3bit目 if((layer[i+j]&BIT3)==BIT3) { Output[i+j+flag+5]=0x00; } else { Output[i+j+flag+5]=0xff; } //2bit目 if((layer[i+j]&BIT2)==BIT2) { Output[i+j+flag+6]=0x00; } else { Output[i+j+flag+6]=0xff; } //1bit目 if((layer[i+j]&BIT1)==BIT1) { Output[i+j+flag+7]=0x00; } else { Output[i+j+flag+7]=0xff; } flag=flag+8; } flag=0x00; } //最終的な「fwrite」はここでする。 fwrite(&Output[0],sizeof(unsigned char),width*height,fpt_output); free(layer); free(Output); fclose(fpt); fclose(fpt_output); } return 0;

  • ラベルをRGBに変換する方法

    k=1,2...,n-1,n の値をRGBに変換したいんです。 k=1をR=50,G=89,B=32 という風に。(数字はランダムです) RGBはすべて0~255の範囲です。 近いkのRGBとは離れた色にしたいんです。 画像関係のことなんですが、処理は数学なので投稿しました。 お願いします。

専門家に質問してみよう