C++での画像切り抜き方法と黒い領域の解消

このQ&Aのポイント
  • C++で画像切り抜きする際に黒い領域ができる問題について解説します。
  • 指定した座標を元に画像の切り抜きを行う方法について具体的なコードを示します。
  • 切り抜いた画像の黒い領域をなくす方法についても説明します。
回答を見る
  • ベストアンサー

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); }

この投稿のマルチメディアは削除されているためご覧いただけません。
  • cap13
  • お礼率100% (8/8)

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

  • ベストアンサー
回答No.2

新しいサイズで作成し直すのは CImage::Create() で。 ただし、すでに作成済みのイメージを破棄しておく必要があると思いますので、以下のような形で作成します。 // 既存のイメージがあれば破棄 if (!img2.IsNull()) { img2.Destroy(); } // 新しいサイズで24bitビットマップ作成 img2.Create(Rcpx-Lcpx, Rcpy-Lcpy, 24); また、もしビットマップをピクチャボックスコントロール(CStatic)に割り当てているのであれば、コントロールの SetBitmap() を呼び出して再度関連付ける必要があります。ピクチャコントロールの変数が pic であるなら以下のように。 pic.SetBitmap(img2);

cap13
質問者

お礼

丁寧なご回答ありがとうございます。 fresh_homepieさんの方法でやりたかった処理ができるようになりました。 また色々と質問させていただくと思いますが、お時間ございましたらご回答よろしくお願いいたします。

その他の回答 (1)

回答No.1

添付画像が見えない状態ですし、メンバ定義等も不明で確かなことは言えませんが… コピーしようとしているサイズ (Rcpx-Lcpx, Rcpy-Lcpy) がコピー先領域のサイズ (jpgHeight, jpgWidth) より小さいために、差分領域が黒くなっているのでしょう。 表示を小さくするのであればコピー先CImage(かな?)をコピーするサイズに合った大きさで作り直す必要があります。 その他には、そもそもコピー元のオリジナルイメージであるはずの img1 自体に線を引いたり点を描いたりしているのもまずいのでは? と思いますが…。

cap13
質問者

お礼

ありがとうございました(^^)

cap13
質問者

補足

ご回答ありがとうございます。 著作権に関するご指摘があったため、添付画像は削除させていただきました。 原因についてはfresh_homepieさんのご指摘通りだと思います。 コピー先CImageをコピーするサイズに合った大きさで作り直すとは具体的にどのようにすればいいのでしょうか。 よろしくお願いいたします。

関連するQ&A

  • 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)に変更したいのですが変更されません。 間違っているところなどがあれば教えてください。

  • C++MFCで変数の値が上書きされてしまいます。

    VC++でjpgを読み込んで縮小してモノクロに表示するプログラムを作成しています。画像を走査するときに、あとで使う予定なのでグローバル変数pixに座標と画像の番号と濃度値を保存して、縮小されたモノクロ画像はちゃんと作画されるのですが(縮小化を行う関数内では濃度値も正しい)、別の関数で濃度値を参照すると値がすべて「0」になります。アドバイスいただけたら幸いです。 ヘッダー内での宣言 public: short int pix[490464]; メインダイアログのソース抜粋 void CxxxxxxxxxDlg::Load(int pictbox); CImage img_org, img_little; CBitmap *myBMP; CDC *pDC = m_pict11.GetDC(); CDC myDC; int x, y; COLORREF col; CString buf; int thr; m_thrmono.GetWindowTextA(buf); thr = atoi(buf); img_org.Load(jpgファイル絶対パス); img_little.Create(234, 160, 24, 0); for(y=0; y<(img_little.GetHeight()); y++){ for(x=0; x<(img_little.GetWidth()); x++){ col = img_org.GetPixel((int)(x*3),(int)(y*3)); pix[x,y,pictbox] = GetRValue(col); if(pix[x,y,pictbox]>thr){ pix[x,y,pictbox] = 255; }else{ pix[x,y,pictbox] = 0; } img_little.SetPixel(x, y, RGB((pix[x,y,pictbox]),(pix[x,y,pictbox]),(pix[x,y,pictbox]))); buf.Format("x:%d y:%d pix:%d", x, y, pix[x,y,pictbox]); m_display.AddString(buf); } } (ピクチャーコントロールへの作画) } int CyyyyyyyyyyyDlg::Recog(int pictbox){ CString buf; for(int y=0; y<160; y++){ for(int x=0; x<234; x++){ buf.Format("pict%d x:%d y:%d -> %d", pictbox, x, y, pix[x,y,pictbox]); m_display.AddString(buf); } } return distance; } 上の関数でリストボックス(コントロール変数m_display)には0か255が入っているのですが、下の関数ではリストにはすべて0になってしまいます。

  • 8bit(256色)グレースケール画像の保存

    32bitのRGB画像ではなく、8bitのグレースケール画像を保存したいと考えています。 保存形式は、tiffとbmpのどちらでも構いません。 ですが、以下のような方法では、 アルファチャンネルを含んだ32bitのRGB画像が保存されてしまいます。 (作成中のプログラムの一例)    Dim img As Bitmap    Dim x As Integer    Dim y As Integer    img = New Bitmap(256, 50)    For x = 0 To 255       For y = 0 To 49          img.SetPixel(x, y, Color.FromArgb(x, x, x))       Next    Next    img.Save("gradation.tif", System.Drawing.Imaging.ImageFormat.Tiff) なお、一例として単純なグラデーション画像を保存していますが、 あくまでも一例であり、グラデーション画像を作成することが目的ではありません。 最終的には、VisualBasicのBitmapクラスで作成したbitmap画像を Photoshopで、8bitのグレースケール画像として開けることが理想です。 どうか、アドバイスをよろしくお願い致しますm(__)m

  • classを使って座標軸を求めるコード

    やさしいJavaからの問題です。 次のように、整数値の座標をあらわす MyPoint クラスを作成してください。 フィールド private int x; (X座標) private int y; (Y座標) メソッド public void setX(int px); (X座標を設定する) public void setY(int py); (Y座標を設定する) public int getX(); (X座標を得る) public int setY(); (Y座標を得る) という問題で、回答は以下の通りですが、 class MyPoint { int x; int y; void setX(int px) { x = px; } void setY(int py) { y = py; } int getX() { return x; } int getY() { return y; } } class Sample5 { public static void main(String[] args) { MyPoint p1; p1 = new MyPoint(); p1.setX(10); p1.setY(5); int px = p1.getX(); int py = p1.getY(); System.out.println("p1のX座標は" + px + "Y座標は" + py + "でした。"); } } 教科書の関連の章ではreturnが先に来ているのですが、突然この問題ではvoidから始まっているのですが、int getX()~return y;までとvoid setX~y = py;までの部分 の順番を変えてもいいですか?

    • ベストアンサー
    • Java
  • C言語 格子点が多角形の中にあるかどうか?

    こんにちは. 私はプログラミングを勉強しはじめて3ヵ月くらいです. 今、与えられた多角形(例えば、(0,0),(3,7),(5,7),(8,3),(4,1),(1,0)の五点からなる多角形)の内部に格子点が存在するかどうかをチェックする(存在すれば1を返す等)ということをプログラミングを利用して,解決したいと思っています.最終的にはそれを利用して与えられた多角形をビットマップ表示にすることが目的です. 現在ある一つの自分の決めた点に関しては与えられた多角形を打ち込むことによって中か外かを判定する関数はできているのですが、100×100個の計10000個分の格子点に関してすべて中にあるか外にあるかを判定したいのですが、なかなか上手くいきません. 分かる方いらっしゃいましたら、アドバイスやプログラムの方よろしくお願いします. 今できているプログラムをのせておきます. #include <stdio.h> #include <stdlib.h> /* #define JUST_ON 2 */ #define JUST_ON 1 int insidePolygon(int x, int y, int pn, int *px, int *py); int insidePolygon(int x, int y, int pn, int *px, int *py) /* x and y are the vertex I want to know in polygon. pn is the number of vertex of polygon *px and *py are the vertex of polygon */ { int i, j; int inside; double yy; if (pn < 1) return 0; if (pn == 1) return x==px[0] && y==py[0]; /* Point (x,y) just lies on the edge or vertex of polygon */ for (i = 0, j = pn-1; i < pn; j = i++) { if (py[i] == py[j] && y == py[i] && ((px[i]<=x && x<=px[j]) || (px[j]<=x && x<=px[i]))) return JUST_ON; else if (py[i] != py[j] && ((py[i]<=y && y<=py[j]) || (py[j]<=y && y<=py[i])) && x == (double)(px[j]-px[i])*(y-py[i])/(py[j]-py[i])+px[i]) return JUST_ON; } /* Point (x,y) is inside/outside polygon */ inside = 0; yy = y + 0.5; /* shift y to avoid acrossing the poly's edges or vertices */ for (i = 0, j = pn-1; i < pn; j = i++) { if (((py[i]<=y && y<py[j]) || (py[j]<=y && y<py[i])) && x < (double)(px[j]-px[i])*(yy-py[i])/(py[j]-py[i])+px[i]) inside = !inside; } return inside; } int main() { int ii; int xx, yy; int pnpn; int pxpx[100], pypy[100]; int ret; printf("Enter (x,y) of a point -> "); scanf("%d %d", &xx, &yy); printf("Enter the number of vertics of the polygons -> "); scanf("%d", &pnpn); for (ii= 0; ii < pnpn; ii++) { printf("Enter %d-th vertics's (x, y) -> ", ii+1); scanf("%d %d", &pxpx[ii], &pypy[ii]); } ret = insidePolygon(xx, yy, pnpn, pxpx, pypy); if (ret == 0) printf("The point is outside the polygon.\n"); else printf("The point is inside the polygon\n"); }

  • OpenCv 透明度について

    OpenCv 透明度について 透明度を表すRGBAのA(アルファチャネル)をいじって画像の透明にしたいのですが、いじってみてもなにも変化がありません。 なにが悪いのかわかりません ↓こんな感じでやってます。 // 画像を読み込む src_img = cvLoadImage(src_imgfile,CV_LOAD_IMAGE_COLOR); //RGBA変換 dst_img = cvCreateImage(cvGetSize(bg_img),IPL_DEPTH_8U,4); cvCvtColor(bg_img,dst_img,CV_RGB2RGBA); //透明度をいじる for ( int y = 0 ; y < dst_img->height ; y++ ) { for ( int x = 0 ; x < dst_img->width ; x++ ) { dst_img->imageData[dst_img->widthStep * y + x * 4 + 3] = -255; } }

  • Cプログラムが円ではなく楕円になってしまう

    円を描くCプログラムを書きたいのですが、 楕円形になってしまいます。どこが間違っていますか。 御教示ください。 main () { int x,y1,y2; double pow(), d ; openwindow(100,100,"02kc951:1-3",3); setfgcolorbyRGB(255,255,255); for(x=0;x<100;x++) { d = pow(-100.0,2.0)-(4*pow(50.0,2.0)-pow(40.0,2.0)+pow(x-50.0,2.0)); /* 判別式 */ if( d>=0 ) { y1=(100-sqrt(d))/2.0; /* y1を求める*/ y2=(100+sqrt(d))/2.0; /* y2を求める*/ setpixel(x,y1); setpixel(x,y2); } } closewindow(); }

  • OpenCVを使った画像の切り抜き

    添付画像のように、サイズ(X,Y)の画像があったとします。 その画像のある座標(X',Y')とサイズを指定してできた短形領域を、IplImageとして保存するにはどうすればいいのでしょうか? OpenCVを使ってるのですが、そういった関数はなかったでしょうか? よろしくお願いします。

  • 色描画

    以下は、ウインドウプロシージャ内でのプログラムです。 RGB( )ですが、0xFFは、255の事ですよね? x*0xFF/rect.rightこの計算式は、何を求めているんですか? 教えてください。 HDC         hdc; PAINTSTRUCT  ps; COLORREF    color; LONG        x,y; RECT        rect; switch(umsg){   case  WM_PAINT:       hdc =BeginPaint(hwnd,&ps);       GetClientRect(hwnd,&rect);       for(y=0;y<rect.bottom;y++){          for(x=0;x<rect.right;x++){            color=RGB(x*0xFF/rect.right,0,0);            SetPixel(hdc,x,y,color);          }       }

  • openCVでの白黒画像読み込み

    いつも大変お世話になっております。 ピクセルの値を「ゼロ(黒)」にしたピクセルを読み込んでも「255(白)」となってしまい困っています。cvShowImageでこの画像を表示すると、どうみてもその場所は黒です。 なぜ「255(白)」になるのかわからず困っています。 原因を教えていただけませんでしょうか。 詳細は以下のとおりです。 out_imgという変数名のCV_LOAD_IMAGE_COLORの真っ白の画像 out_img = cvLoadImage("C:...\shiro.jpg", CV_LOAD_IMAGE_COLOR); の6×6ピクセルの値を、以下の文で「黒」にして    out_img->imageData[out_img->widthStep * 6 + 6 * 3] = 0;    out_img->imageData[out_img->widthStep * 6 + 6 * 3 + 1] = 0;    out_img->imageData[out_img->widthStep * 6 + 6 * 3 + 2] = 0; 保存し、再び(別のソリューションで)src_img変数としてこの画像を読み込み    src_img = cvLoadImage("C:...¥shiro.jpg", CV_LOAD_IMAGE_COLOR); グレースケール化し、       src_img_gray = cvCreateImage(cvGetSize(src_img), IPL_DEPTH_8U, 1); tmp_img = cvCreateImage(cvGetSize(src_img), IPL_DEPTH_8U, 1 ゼロイチの2値化(バイナリ画像)に変換し、 cvCvtColor(src_img, src_img_gray, CV_BGR2GRAY); 閾値でゼロイチに変換した後(なぜか上のsrc_img_grayでは黒がゼロにはならないため) cvAdaptiveThreshold(src_img_gray, tmp_img, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 7, 8); 6×6の位置の値(変数iro)を確認すると「255」となります。 for (x = 0; x < tmp_img->width; x = x + 1){ // x 座標を 1ピクセルずつ進める for (y = 0; y < tmp_img->height; y = y + 1){ // y 座標を 1ピクセルずつ進める if (x == 6 && y == 6){ x = 6; (ここでデバックを掛けて、下の変数iroの値がいくつかを確認しています。ゼロであってほしいのですが、255です。 } uchar iro = tmp_img->imageData[tmp_img->widthStep * y + x * 3]; if (iro == 0){ 画像読み込みの引数がおかしいのだろうと思い、 CV_LOAD_IMAGE_ANYCOLOR や「0」にしたところ 今度はfor文のところでエラーになり、走査が始まりません。 for (x = 0; x < tmp_img->width; x = x + 1){ // x 座標を 1ピクセルずつ進める for (y = 0; y < tmp_img->height; y = y + 1){ // y 座標を 1ピクセルずつ進める 初歩的な質問で申し訳ありません。 ぜひアドバイスをいただけると助かります。 どうぞよろしくお願い致します。