• ベストアンサー

複数枚画像の合成

こんにちわ、Visual Studio 2005のフォームアプリケーションでプログラミングしているものです。複数枚の画像を一つの画像にしたいのですが、どうもあっているのかどうかわかりません。 たとえば、画像が9枚あって1枚目の一番左上の画素を[0-0,0]とすると、 [0-0,0][1-0,0][2-0,0]|[3-1,0][4-1,0][5-1,0]|[6-2,0][7-2,0][8-2,0] [0-0,0][1-0,0][2-0,0]|[3-1,0][4-1,0][5-1,0]|[6-2,0][7-2,0][8-2,0] [3-0,0][4-0,0][5-0,0]|[6-1,0][7-1,0][8-1,0]|[0-2,0][1-2,0][2-2,0] [3-0,0][4-0,0][5-0,0]|[6-1,0][7-1,0][8-1,0]|[0-2,0][1-2,0][2-2,0] [6-0,0][7-0,0][8-0,0]|[0-1,0][1-1,0][2-1,0]|[3-2,0][4-2,0][5-2,0] [6-0,0][7-0,0][8-0,0]|[0-1,0][1-1,0][2-1,0]|[3-2,0][4-2,0][5-2,0] -----------------+-----------------+------------------------ [0-0,1][1-0,1][2-0,1]|[3-1,1][4-1,1][5-1,1]|[6-2,1][7-2,1][8-2,1] [0-0,1][1-0,1][2-0,1]|[3-1,1][4-1,1][5-1,1]|[6-2,1][7-2,1][8-2,1] [3-0,1][4-0,1][5-0,1]|[6-1,1][7-1,1][8-1,1]|[0-2,1][1-2,1][2-2,1] [3-0,1][4-0,1][5-0,1]|[6-1,1][7-1,1][8-1,1]|[0-2,1][1-2,1][2-2,1] [6-0,1][7-0,1][8-0,1]|[0-1,1][1-1,1][2-1,1]|[3-2,1][4-2,1][5-2,1] [6-0,1][7-0,1][8-0,1]|[0-1,1][1-1,1][2-1,1]|[3-2,1][4-2,1][5-2,1] -----------------+-----------------+------------------------ [0-0,2][1-0,2][2-0,2]|[3-1,2][4-1,2][5-1,2]|[6-2,2][7-2,2][8-2,2] [0-0,2][1-0,2][2-0,2]|[3-1,2][4-1,2][5-1,2]|[6-2,2][7-2,2][8-2,2] [3-0,2][4-0,2][5-0,2]|[6-1,2][7-1,2][8-1,2]|[0-2,2][1-2,2][2-2,2] [3-0,2][4-0,2][5-0,2]|[6-1,2][7-1,2][8-1,2]|[0-2,2][1-2,2][2-2,2] [6-0,2][7-0,2][8-0,2]|[0-1,2][1-1,2][2-1,2]|[3-2,2][4-2,2][5-2,2] [6-0,2][7-0,2][8-0,2]|[0-1,2][1-1,2][2-1,2]|[3-2,2][4-2,2][5-2,2] といった感じにしようと思っています。 画像には配列を使っていてbmp[0]~[8]が9枚の画像を表し、picはbmp[0]~[8]の画像一枚に対してサイズが横3倍縦6倍の画像になるはずです。 自分でプログラムしたのですが、できた画像を拡大しても細かすぎてよくわからない状況です。 for ( y = 0; y < h; y += 6 ) {  for ( x = 0; x < w; x += 3 ) {   for( b = 0; b < 3; b++ ) {    for( a = 0; a < 3; a++ ) {      pic->SetPixel( x + a, y + (2 * b) , bmp[((2 * b) * 3 + a + x) % 9]->GetPixel( x / 3, y / 6 ) );      pic->SetPixel( x + a, y + (2 * b) , bmp[(((2 * b) + 1) * 3 + a + x) % 9]->GetPixel( x / 3, y / 6 ) );    }   }  } } 以前に、同じような配置法なのですが横3倍縦3倍の合成画像として、 [0-0,0][1-0,0][2-0,0]|[3-1,0][4-1,0][5-1,0]|[6-2,0][7-2,0][8-2,0] [3-0,0][4-0,0][5-0,0]|[6-1,0][7-1,0][8-1,0]|[0-2,0][1-2,0][2-2,0] [6-0,0][7-0,0][8-0,0]|[0-1,0][1-1,0][2-1,0]|[3-2,0][4-2,0][5-2,0] -----------------+-----------------+------------------------ [0-0,1][1-0,1][2-0,1]|[3-1,1][4-1,1][5-1,1]|[6-2,1][7-2,1][8-2,1] [3-0,1][4-0,1][5-0,1]|[6-1,1][7-1,1][8-1,1]|[0-2,1][1-2,1][2-2,1] [6-0,1][7-0,1][8-0,1]|[0-1,1][1-1,1][2-1,1]|[3-2,1][4-2,1][5-2,1] -----------------+-----------------+------------------------ [0-0,2][1-0,2][2-0,2]|[3-1,2][4-1,2][5-1,2]|[6-2,2][7-2,2][8-2,2] [3-0,2][4-0,2][5-0,2]|[6-1,2][7-1,2][8-1,2]|[0-2,2][1-2,2][2-2,2] [6-0,2][7-0,2][8-0,2]|[0-1,2][1-1,2][2-1,2]|[3-2,2][4-2,2][5-2,2] の配置プログラムとして、 for ( y = 0; y < h; y += 3 ) {  for ( x = 0; x < w; x += 3 ) {   for( b = 0; b < 3; b++ ) {    for( a = 0; a < 3; a++ ) {      pic->SetPixel( x + a, y + b , bmp[(b * 3 + a + x) % 9]->GetPixel( x / 3, y / 3 ) );    }   }  } } との回答をいただいたので、これを参考に作ってみたのですが・・・。 説明が下手でわかりにくいかもしれませんが、お分かりの方がいましたらご教授お願いします。

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

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8525/19379)
回答No.2

>     pic->SetPixel( x + a, y + (2 * b) , bmp[((2 * b) * 3 + a + x) % 9]->GetPixel( x / 3, y / 6 ) ); >     pic->SetPixel( x + a, y + (2 * b) , bmp[(((2 * b) + 1) * 3 + a + x) % 9]->GetPixel( x / 3, y / 6 ) ); 間違ってる。 偶数ラインと奇数ラインは、同じbmpから同じデータを持って来るはず。 なので、3つ目の引数は、2行とも同じにならないとおかしい。 そして「縦が6倍でも、縦が3倍でも、持って来る方法は同じ」じゃないといけない(但し、yの増加が3から6になってるので、そこだけ変更しないといけない) また「横は変わってない」「持って来る方法は同じ」なのだから「縦3倍と縦6倍の時で、1番目と3番目の引数は同じ」にならないとならない。 つまり「変えるは2番目の引数だけ」になる。 3倍の時が      pic->SetPixel( x + a, y + b , bmp[(b * 3 + a + x) % 9]->GetPixel( x / 3, y / 3 ) ); だったのなら、6倍の時は「2番目の引数だけ変える」のだから偶数ラインは      pic->SetPixel( x + a, ???, bmp[(b * 3 + a + x) % 9]->GetPixel( x / 3, y / 6 ) ); になる筈。 奇数ラインは偶数ラインの1ライン下だから      pic->SetPixel( x + a, ??? + 1, bmp[(b * 3 + a + x) % 9]->GetPixel( x / 3, y / 6 ) ); になる筈。 で、6倍のプログラムは、yは6づつ増えてて、bは1づつ増えてる。 y、b、偶数ラインの位置、奇数ラインの位置を表にすると y b 偶数ラインの位置 奇数ラインの位置 0 0 0              1 0 1 2              3 0 2 4              5 6 0 6              7 6 1 8              9 6 2 10              11 12 0 12              13 12 1 14              15 12 2 16              17 となる。 この表に合うように「???」の式、「??? + 1」の式を書けば良い事になる。 すると「???」は「y + b * 2」だと判る。 上記を踏まえて書き直すと for ( y = 0; y < h; y += 6 ) {  for ( x = 0; x < w; x += 3 ) {   for( b = 0; b < 3; b++ ) {    for( a = 0; a < 3; a++ ) {      pic->SetPixel( x + a, y + b * 2, bmp[(b * 3 + a + x) % 9]->GetPixel( x / 3, y / 6 ) );      pic->SetPixel( x + a, y + b*2+1, bmp[(b * 3 + a + x) % 9]->GetPixel( x / 3, y / 6 ) );    }   }  } } となる。 しかし「同じデータを2度取り出す」のだから「取り出すのは1回」で良い筈。 従って TColor col; for ( y = 0; y < h; y += 6 ) {  for ( x = 0; x < w; x += 3 ) {   for( b = 0; b < 3; b++ ) {    for( a = 0; a < 3; a++ ) {      col = bmp[(b * 3 + a + x) % 9]->GetPixel( x / 3, y / 6 );      pic->SetPixel( x + a, y + b * 2, col);      pic->SetPixel( x + a, y + b*2+1, col);    }   }  } } とすれば良い。

judas15
質問者

お礼

分かりやすい説明ありがとうございます。 拡大してみると、ちゃんとした画像ができているのがハッキリわかりました。 縦だけではなくて、横も変えてみた結果うまくいきました。 ありがとうございます。

その他の回答 (1)

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.1

元が9枚しかない画像で24倍の画像を作るのでしょうか? 3x3ならば9倍ですから9枚の画像から生成しても隙間は出来ません 元が2x2ぐらいのマトリックスでどのように配置するのか提示してみましょう

judas15
質問者

お礼

回答ありがとうございます。 縦を2倍にして、横はそのままの1倍にしようとしていました。 なので結果的には元画像(例えばbmp[0])の縦6倍、横3倍の画像を作ろうとしていたわけです。 縦に同じ画像の画素を2つづつ配置しています。 やっぱり、説明わかりにくかったですね・・・すみません。 今回は別の方に詳しい説明をいただいた結果画像がしっかり生成されました。 せっかく回答いただいたのにすみません、いつもありがとうございます^^

関連するQ&A

  • Bitmapデータ型の画像幅の拡大

    現在Visual studio 2005のフォームアプリケーションでプログラミグを行っている者です。以下のプログラムの中に画像の幅であるw,hという変数があるのですが、私の作ろうとしている画像処理の関係上、この画像データの幅を倍にしたいです(例:3*w,3*h)。しかし、変数宣言(例:int 3*w)やfor文の中で倍にしようとしても、ビルドはできるものの"アプリケーションのコンポーネントで、ハンドルされていない例外が発生しました。・・・パラメータは正の値で、高さより小さい値指定しなければなりません。"とでて、実行できません。おそらく倍にしてあげたとこで、倍になった部分の画像データがわからないためこういったエラーが出てしまうのだと考えています。どうにかして、BITMAPデータ型で読み込んだ画像の幅を倍の数値を得たいのですが、エラーのでないようにするためにはどのようにしてあげればいいのでしょうか?わかる方がいたらよろしくお願いします。 プログラムは以下のとおりです。 #pragma once // 省略 // } #pragma endregion private:Bitmap^ pic; private:array< Bitmap^>^ bmp; // 原画像格納 // private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) { bmp[0] = gcnew Bitmap("画像ファイル1",true); pictureBox1->Image = bmp[0]; pic = gcnew Bitmap("画像ファイル2",true); } private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) { int x,y,a,b; /* x,y: 画像の座標 a,b: 複合画像の座標 */ int w = pic->Width; //ここでpic->Width*3としてもエラー /* 複合画像の横幅 */ int h = pic->Height; /* 複合画像の縦幅 */ x = 0; y = 0; a = 0; b = 0; for(y = 0; y < h; y++){ //ここで3*hとしてもエラー for(x = 0; x < w; x+=3){ pic->SetPixel( x, y, bmp[1]->GetPixel( x, y ) ); } } pictureBox2->Image = pic; } }; }

  • 線形補間法プログラム(C++)

    C++言語で線形補間法のプログラムを組んで実行しているのですが、どしてもうまくいきません。ただ2倍の画像を作っているだけなのですが・・・。 以下プログラムを載せます、おおよその場所はわかるのですがどうすれば通るのかわかりません。どう直したらよいのか分かる方がいましたらご教授お願いします。 ※bmp[0]:現画像 pic:bmp[0]の縦横2倍の画像 // 線形補間法 // int zx = 2; int zy = 2; int i,j,m,n; float x,y,p,q; int xs = bmp[0]->Width/2; int ys = bmp[0]->Height/2; int d; for(i = -ys; i < ys; i++){ for(j = -xs; j < xs; j++){ y = i/zy; x = j/zx; if(y > 0){ m = (int)y; }else{ m = (int)(y-1);} if(x > 0){ n = (int)x; }else{ n = (int)(x-1);} q = y - m; p = x - n; if(q == 1){q = 0; m = m + 1;} if(p == 1){p = 0; n = n + 1;} if((m >= -ys)&&(m < ys)&&(n >= -xs)&&(n < xs)){ d = (int)((1.0 - q) * (1.0 - p) * (bmp[0]->GetPixel( m + ys, n + xs)) //おそらくこの辺に問題があるかと思われます。 + p * (bmp[0]->GetPixel( m +ys, n + xs)) + q * (1.0 - p) * (bmp[0]->GetPixel(m + 1 + ys, n + xs)) + p * (bmp[0]->GetPixel(m + 1 + ys, n + 1 + xs))); }else{ d = 0; } if(d < 0){d = 0;} if(d > 255){d = 255;} pic->SetPixel(i + ys, j + xs) = d; } } pictureBox2->Image = pic; }

  • C#について

    C#で画像の色を変更しようと頑張っているのですが・・・ クリックした座標と同じ色の場所を青にしたいです。 XとYは画像の座標の大体の最大値です。 public partial class Form1 : Form { Bitmap bmp; public Form1() { InitializeComponent(); bmp = new Bitmap(pB1.Image); } private void pictureBox1_MouseDown(object sender, MouseEventArgs e) { Color c = bmp.GetPixel(e.X, e.Y); for (int Y = 0; Y < 280; Y++) { for (int X = 0; X < 240; X++) { Color c2 = bmp.GetPixel(X, Y); if (c.R == c2.R && c.G == c2.G && c.B == c2.B) { bmp.SetPixel(X, Y, Color.FromArgb(0, 0, 255)); } } } } } } クリックしたところと同じ色を青(0, 0, 255)に変更したいのですが変更されません。 間違っているところなどがあれば教えてください。

  • BMP画像を画像処理して連続に表示したいですが?

    プログラミングの初心者ですが、現在VC++2005のフォームアプリケーションでプログラムについて勉強しています。画像を連続表示するところで、わからなくなってしまったので、みなさんのご指導お願いいたします。 やりたい処理は、取り込んだ画像の色を変化させて、順番に表示したい 処理です。作成したプログラムは下記のようになります。 前略 for(n=0; n<256; n+=20){ for(y=0; y<480; y++){ for(x=0; y<640; x++){ bmp->Setpixel(x, y, Color::FromArgb(n, n, n)); } } pictureBox->Image = bmp; Thread::Sleep(2000); } nの値をbmpに入れてから一回表示し、さらにnを足してからbmpに入れて表示するといった流れですが、Sleepを入れても何にも表示されません。 どういったところは不具合なのかをよくわかりません。 ご指導をいただければ感謝致します。どうぞよろしくお願い致します。

  • 画像の抽出

    今、VB2008を用いて、原画像と原画像に落書きをした画像の2枚を用いて、 落書きのみを抽出するプログラムを作っているのですが、 RGBの演算がどうも上手く出来ません。 コードは Dim r1#, g1#, b1#, r2#, g2#, b2#, r3#, g3#, b3#      Dim i%, j%, nx%, ny%      Dim col1, col2 As Color '略     For j = 0 To ny - 1      For i = 0 To nx - 1       col1 = bmp1.GetPixel(i, j)'落書きした画像         r1 = col1.R         g2 = col1.G         b3 = col1.B      col2 = bmp2.GetPixel(i, j)'落書き前の原画像         r2 = col2.R         g2 = col2.G         b2 = col2.B      r3 = r1 - r2       g3 = g1 - g2     b3 = b1 - b2    bmp3.SetPixel(i, j, Color.FromArgb(Int(r3), Int(g3), Int(b3)))'落書きのみ抽出された画像の書き込み     Next    Next Form1.Picturebox1.Image = bmp3 としてみたのですが、gやbの値が - になってしまい、エラーが出て しまいます。If(g3<255) then g3 =255 などと記載してみたのですが上手くいきませんでした。 どこを修正、加筆すればうまく抽出が出来る様になるのでしょうか。

  • C++での画像切り抜きについて

    こんにちは。プログラミング初心者です。 Microsoft Visual Studio C++ MFCで画像解析のプログラムを書いています。 その際、jpg画像から左上隅・右下隅の座標を指定してある領域を切り出したいのですが、 今の方法では切り出した画像の周りに黒の領域ができてしまいます。(添付画像参照) サイズを切り抜いた画像のサイズに変更して、黒の領域をなくしたいのですが、 どのように書けばいいのでしょうか? 下記のコードに追加する部分・変更する部分を具体的に教えていただけると有難いです。 説明不足で申し訳ありませんが、よろしくお願いいたします。 void CtestbView::OnUleft() //左上隅点の座標 { // TODO: ここにコマンド ハンドラー コードを追加します。 Lcpx=px; //左上隅のx座標 Lcpy=py; //左上隅のy座標 } void CtestbView::OnDright() //右下隅点を指定するサブルーチン { // TODO: ここにコマンド ハンドラー コードを追加します。 int x,y; Rcpx=px;//右下隅x座標 Rcpy=py;// y for(y=Lcpy-1; y<=Rcpy+1; y++) {//切り出し範囲を白線で囲む(白線を切り出さないため+-1を付加) img1.SetPixel(Lcpx-1,y,RGB(255,255,255)); //左側縦線 img1.SetPixel(Rcpx+1,y,RGB(255,255,255)); //右側縦線 } for(x=Lcpx-1; x<=Rcpx+1; x++) { img1.SetPixel(x,Lcpy-1,RGB(255,255,255)); //上側横線 img1.SetPixel(x,Rcpy+1,RGB(255,255,255)); //下側横線 } jpgLoadFlag1=true; Invalidate(); } void CtestbView::OnCut() //テンプレートを切り出すサブルーチン { // TODO: ここにコマンド ハンドラー コードを追加します。 int x,y; BeginWaitCursor(); for(y=0; y<jpgHeight; y++) for(x=0; x<jpgWidth; x++) img2.SetPixel(x,y,RGB(0,0,0)); //画面をクリア int xshift=0; int yshift=0; for(y=Lcpy; y<=Rcpy; y++) { for(x=Lcpx; x<=Rcpx; x++) { COLORREF color=img1.GetPixel(x,y); int RV=GetRValue(color); int GV=GetGValue(color); int BV=GetBValue(color); img2.SetPixel(x-Lcpx+xshift,y-Lcpy+yshift,RGB(RV,GV,BV)); } } xminP=xshift; xmaxP=Rcpx-Lcpx+xshift; //テンプレート上のパターンの位置 yminP=yshift; ymaxP=Rcpy-Lcpy+yshift; jpgWidth=xmaxP; jpgHeight=ymaxP; jpgLoadFlag2=true; Invalidate(); EndWaitCursor(); } void CtestbView::OnLButtonDown(UINT nFlags, CPoint point) //指定点の座標値を取り出す { // TODO: ここにメッセージ ハンドラー コードを追加するか、既定の処理を呼び出します。 CView::OnLButtonDown(nFlags, point); int i,j; int x,y; px=point.x; //マウス指定点のx座標 py=point.y; //マウス指定点のy座標 COLORREF color=img1.GetPixel(px,py); //指定点のアドレス変換 rv=GetRValue(color); //マウス指定点の赤成分 gv=GetGValue(color); //マウス指定点の緑座標 bv=GetBValue(color); //マウス指定点の青座標 img1.SetPixel(px, py, RGB(255,0,0));//指定点位置の赤点表示 for(j=0; j<=20; j++)//指定点の色を20×20の短径で表示 for(i=0; i<=20; i++) img1.SetPixel(jpgWidth-30+i,20+j,RGB(rv,gv,bv)); //指定点の色設定 jpgLoadFlag1=true; InvalidateRect(NULL); }

  • 細線化のプログラム

    細線化のプログラム C#で細線化のプログラムを作成してみましたがうまくいきません。 http://imagingsolution.blog107.fc2.com/blog-entry-138.html を参考に作成しました。 うまくいかないところは、一部に縦線がいくつも残ってしますところです。 ソース static Bitmap Shape(Bitmap bmp) { int Flag = 0; //初期化 for (int j = 0; j < bmp.Height ; j++) { for (int i = 0; i < bmp.Width ; i++) { if (bmp.GetPixel(i, j).R != 255) { bmp.SetPixel(i, j, Color.FromArgb(0, 0, 0)); } } } while(true){ //パターン1 for (int i = 1; i < bmp.Width - 1; i++) { for (int j = 1; j < bmp.Height - 1; j++) { if (bmp.GetPixel(i, j).R == 255) { //除去しないパターン if (( 略 )) { //セーフ } else if ((略)){ //セーフ } //除去するパターン else if ((bmp.GetPixel(i + 1, j).R != 255) || (bmp.GetPixel(i, j - 1).R != 255)) { //黒にする bmp.SetPixel(i, j, Color.FromArgb(0, 0, 0)); Flag++; } } } } // MessageBox.Show(Flag.ToString()); //終了 if (Flag == 0) return bmp; Flag = 0; /*パターン2も同じようにする*/ という感じでプログラムを組んでいます。 画像は失敗例です。アドバイスをお願いします

    • 締切済み
    • CGI
  • Photoshopで複数の画像を合成させる際、画像の大きさを合わせるには?

    Adobe Photoshop CS2を使っていて、Photoshopで画像Aと画像Bを合体させようとしています。 画像Aに余白を作って、そこに画像Bを持ってくるのですが、画像Aに比べて画像Bが大きくなってしまい(画像Aに比べて、画像Bは倍くらいの大きさで表示されます)、 画像Bの大きさを小さくしたいのですが、どういった操作をすればいいのでしょうか?

  • uwscで画像がうまく認識できない

    while 1 if CHKIMG("gazou/A.bmp",-1,,,,) > 0 then break wend で画面上にAという画像は認識した後、 その少し左隣にあるBという画像を認識したいのですが上手くいきません while 1 if CHKIMG("gazou/B.bmp",-1,G_IMG_X-24,G_IMG_Y-7,G_IMG_X-1,G_IMG_Y+24) > 0 then break wend という感じでやったらループから帰ってこなくなりました 座標を G_IMG_X-24,G_IMG_Y-7,G_IMG_X-1,G_IMG_Y+24 から普通の数字の組み合わせにしたらちゃんと認識できたので この書き方が間違っているというのはわかるんですが、 どうしてもAの画像の座標から左にずれたこの位置を指定したいのです。 ですが自分はこの書き方以外知らないのです・・・ Aの画像を認識した後に、 そのAの画像があった座標から(X-27,Y-7,X-1,Y+24)ほどずれた位置を指定して その範囲にB画像があるかどうか確かめるということをするには どうすればいいのでしょうか?

  • 画素へのアクセスについて困っています。

    現在VC++2005でプログラムを組んでいますが、画素に対するアクセスをしたいですが、getpixel()以外の方法がありますか? 自分がやっているのは以下のようになります。 Color color = bmp->Getpixel(x,y); r = color.R, g = color.G, b = color.B; 下のようなアクセスを行いたいですが、フォームアプリケーションではどうすればよいでしょうか。 B = Bmpimage[x*3+y*bmpL]; G = Bmpimage[x*3+y*bmpL+1]; R = Bmpimage[x*3+y*bmpL+2]; ご教授よろしくお願いします。