7 segment digits検出のためのテンプレート準備

#1 TImage上でのマウスドラッグを処理して矩形領域を指定

の続きです。プロトタイプを動かしてみましょう。

ここで”Open”。

こうたどって前回の”frame0.jpg”を選択すると、

こうなるので、画像上でマウスをドラッグします。

左上で左クリックして、クリックしたまま右下までドラッグします。でボタンを離す。その状態が上図で、”AddRect”をクリックすると、

これでRect(矩形領域)が切り取れましたので、これで良ければ”Save”。

セーブされたファイルが上図です。プログラムを示しましょう。まずフォームは、

TImagex2,TButtonx3,TOpenDialogx1を上図のように配置。Unit1.hは、

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ExtCtrls.hpp>
#include <Vcl.Dialogs.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE で管理されるコンポーネント
	TImage *Image1;
	TButton *Open;
	TOpenDialog *OpenDialog1;
	TButton *AddRect;
	TImage *Image2;
	TButton *Save;
	void __fastcall FormDestroy(TObject *Sender);
	void __fastcall Image1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift,
          int X, int Y);
	void __fastcall Image1MouseMove(TObject *Sender, TShiftState Shift, int X, int Y);
	void __fastcall Image1MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift,
          int X, int Y);
	void __fastcall FormPaint(TObject *Sender);
	void __fastcall OpenClick(TObject *Sender);
	void __fastcall AddRectClick(TObject *Sender);
	void __fastcall SaveClick(TObject *Sender);

private:	// ユーザー宣言
    bool FDrawing;     // ドラッグ中かどうかのフラグ
    TPoint FStartPos;  // マウスを押し下げた初期座標
	TPoint FLastPos;   // 直前のマウス座標(線を消す用)
    TPoint FEndPos;
	TBitmap *FBkBmp;   // 背景画像を一時保存するビットマップ

public:		// ユーザー宣言
	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

Unit1.cppは、

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop
#include <jpeg.hpp>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
int width;
int height;
int vheight;

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}

void LoadJpegFile(const AnsiString & Src,
							Graphics::TBitmap * Bitmap)
{
		TJPEGImage * Jpeg = new TJPEGImage();

	Jpeg->Performance = jpBestQuality;
		Jpeg->PixelFormat = jf24Bit;
		Jpeg->Grayscale = false;
		Jpeg->LoadFromFile(Src);

		Bitmap->HandleType = bmDIB;
		Bitmap->PixelFormat = pf32bit;
		Bitmap->Width = Jpeg->Width;
		width = Jpeg->Width;
		Bitmap->Height = Jpeg->Height;
		height = Jpeg->Height;
		Bitmap->Canvas->Draw(0,0,Jpeg);

		vheight = 640* height / width ;

		delete Jpeg;
}

//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
     delete FBkBmp;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Image1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift,
          int X, int Y)
{
    if (Button == mbLeft) // 左クリックのみ対象
    {
        FDrawing = true;
        FStartPos = Point(X, Y);
        FLastPos = Point(X, Y);

        // 現在の Image1 の状態(背景)を FBkBmp にコピーして保存
        FBkBmp->Assign(Image1->Picture->Bitmap);
    }

}
//---------------------------------------------------------------------------
void __fastcall TForm1::Image1MouseMove(TObject *Sender, TShiftState Shift, int X,
          int Y)
{
     if (FDrawing)
    {
        // 毎回バックアップから背景を書き戻す(古いドラッグ枠を消すため)
        Image1->Picture->Bitmap->Assign(FBkBmp);

        // 描画設定
        Image1->Canvas->Pen->Color = clRed;
        Image1->Canvas->Pen->Width = 1;
        Image1->Canvas->Brush->Style = bsClear; // 中は透明

        // 開始位置から現在のカーソル位置まで四角形を描画
        Image1->Canvas->Rectangle(FStartPos.x, FStartPos.y, X, Y);

		// 画面更新

		FEndPos.x = X;
		FEndPos.y = Y;

        Image1->Refresh();
    }

}
//---------------------------------------------------------------------------
void __fastcall TForm1::Image1MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift,
          int X, int Y)
{
    if (Button == mbLeft && FDrawing)
    {
        FDrawing = false; // ドラッグ終了

        // 最後に確定した図形を描画
        Image1->Canvas->Pen->Color = clRed;
        Image1->Canvas->Pen->Width = 1;
        Image1->Canvas->Brush->Style = bsClear;
        Image1->Canvas->Rectangle(FStartPos.x, FStartPos.y, X, Y);

        Image1->Refresh();
    }

}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
		//Graphics::TBitmap * Bitmap = new Graphics::TBitmap();
		//LoadJpegFile("IMG_0201.JPG",Bitmap);
		//Image1->Canvas->Draw(0,0,Bitmap);
		//delete Bitmap;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::OpenClick(TObject *Sender)
{
	if( OpenDialog1->Execute()){
        	FDrawing = false;
		FBkBmp = new TBitmap();

		LoadJpegFile(OpenDialog1->FileName,FBkBmp);
		//Image1->Canvas->Draw(0,0,FBkBmp);
		TRect dest = {0,0,640,vheight};

		Image1->Height = vheight;
        Image1->Width = 640;

		//Image1->Canvas->Draw(dest,FBkBmp);
		Image1->Canvas->StretchDraw(dest,FBkBmp);
		//Canvas->StretchDraw()




	}
}
//---------------------------------------------------------------------------

void __fastcall TForm1::AddRectClick(TObject *Sender)
{
	TRect area = { FStartPos.X+1,FStartPos.Y+1,FEndPos.X-1,FEndPos.Y-1};

	int	width2 = area.Width();
	int	height2 = area.Height();

	Image2->Width = width2;
	Image2->Height = height2;


	TRect dst = {0,0,Image2->Width,Image2->Height};

	Image2->Canvas->CopyRect(dst, Image1->Canvas, area);

}
//---------------------------------------------------------------------------

void __fastcall TForm1::SaveClick(TObject *Sender)
{
	Image2->Picture->SaveToFile("output.png");
}
//---------------------------------------------------------------------------

ポイントは、TImage上のイベント処理とjpgを直接Loadしないで、一旦TBitmapで受けてから描画することです。そうしないとTBitmapとImage1->Canvasが結びつかず、実行時エラーになります。そこは、

void LoadJpegFile(const AnsiString & Src,
							Graphics::TBitmap * Bitmap)
{
		TJPEGImage * Jpeg = new TJPEGImage();

	Jpeg->Performance = jpBestQuality;
		Jpeg->PixelFormat = jf24Bit;
		Jpeg->Grayscale = false;
		Jpeg->LoadFromFile(Src);

		Bitmap->HandleType = bmDIB;
		Bitmap->PixelFormat = pf32bit;
		Bitmap->Width = Jpeg->Width;
		width = Jpeg->Width;
		Bitmap->Height = Jpeg->Height;
		height = Jpeg->Height;
		Bitmap->Canvas->Draw(0,0,Jpeg);

		vheight = 640* height / width ;

		delete Jpeg;
}

ですが、まわりくどいですね。このBitmapを

void __fastcall TForm1::OpenClick(TObject *Sender)
{
	if( OpenDialog1->Execute()){
        	FDrawing = false;
		FBkBmp = new TBitmap();

		LoadJpegFile(OpenDialog1->FileName,FBkBmp);
		//Image1->Canvas->Draw(0,0,FBkBmp);
		TRect dest = {0,0,640,vheight};

		Image1->Height = vheight;
        Image1->Width = 640;

		//Image1->Canvas->Draw(dest,FBkBmp);
		Image1->Canvas->StretchDraw(dest,FBkBmp);
		//Canvas->StretchDraw()




	}
}

表示します。TImage上のmouse_down,mouse_move,mouse_upを処理して矩形を描いています。

コメント