【C#】HALCON de 画像処理(拡大/縮小)

スポンサーリンク

特に使う予定はないけど、どうやるのか迷ったの記憶があるうちに紹介します。

今回使用する関数

使う関数としては下記3つになります。

HOperatorSet.HomMat2dIdentity(out HTuple)
   ⇒ 均一な2D行列を生成
HOperatorSet.HomMat2dScale(HTuple, HTuple, HTuple, HTuple, HTuple, out HTuple)
  ⇒ 均一な2D行列に拡大率・縮小率を追加HOperatorSet.AffineTransImage(HObject , out HObject, HTuple, HTuple, HTuple)
  ⇒ 任意のアフィン2D行列を画像に適用(変換)

にわか知識ですが、ホモグラフィー行列の計算(射影変換の一種[拡大縮小])を行って、画像を変換する流れだと思っています。
※こんな細かい事はいいのですw

■HOperatorSet.HomMat2dIdentity(out HTuple)
   第1引数:行列(出力)

■HOperatorSet.HomMat2dScale(HTuple, HTuple, HTuple, HTuple, HTuple, out HTuple)
  第1引数:行列
  第2引数:Y方向のスケール要素(0より大きい事)
  第3引数:X方向のスケール要素(0より大きい事)
  第4引数:基点Y[不動点](単位はピクセル)[0が分かりやすい]
  第5引数:基点X[不動点](単位はピクセル)[0が分かりやすい]
  第6引数:変換後の行列

■HOperatorSet.AffineTransImage(HObject , out HObject, HTuple, HTuple, HTuple)
  第1引数:入力画像
  第2引数:変換後の画像(出力画像)
  第3引数:行列
  第4引数:保管の方法("bicubic","bilinear","constant","nearest_neighbor","weighted")
  第5引数:出力画像のサイズの適用("false" or "true")

※太字は、デフォルト値

難しい事は分かりませんが、流れは下記の通りになります。
①行列を生成
②その行列に回転を加味した行列に変換
③拡大縮小を加味した行列を画像に変換

座学をしても分からないので次に実際に作ってみます。

詳しい事を知りたい方は、下記内容を参考にしてください。
hom_mat2d_identity [HALCON Operator Reference / Version 13.0.4] (mvtec.com)
hom_mat2d_scale [HALCON Operator Reference / Version 13.0.4] (mvtec.com)
affine_trans_image [HALCON Operator Reference / Version 13.0.4] (mvtec.com)

サンプルを作ってみる

簡単に作ってみたいと思います。
【読込】ボタンを押して、ユーザーにファイル選択をしてもらいます。
そして、【拡大・縮小】ボタンが押された時に、設定の4つを取得し、その設定どおりに画像を加工します。

操作画面

下記、簡単にコントロール説明

■btnReadImg
  ⇒ 画像読込のボタン(読み込んだ画像を表示)
■lblReadImgSize
  ⇒ 読み込んだ画像サイズを表示する
■nudRateX/nudRateY
  ⇒ 読み込んだ画像に対して、何倍の拡大縮小を行うかの設定
■nudFixedPointX/nudFixedPointY
  ⇒ 拡大縮小する際に基点(不動点)となる座標
■btnExeRate
  ⇒ 設定を取得し、読み込んだ画像を拡大縮小を行う
■lblRateImgSize
  ⇒ 拡大縮小した後の画像サイズを表示する

全体に使う変数として、読み込んだ画像は、フォーム内で読み書きできるように定義する。

HObject DispOrgImg = null;      //読み込んだ画像

拡大・縮小ボタンを押された時の処理

private void btnExeRate_Click(object sender, EventArgs e)
{
    if (DispOrgImg == null) return;    //読み込んでいるかどうか

    //設定取得
    HTuple sx = (double)nudRateY.Value;
    HTuple sy = (double)nudRateX.Value;
    HTuple px = (int)nudFixedPointY.Value;
    HTuple py = (int)nudFixedPointX.Value;

    //読み込んだ画像を拡大縮小
    HOperatorSet.HomMat2dIdentity(out HTuple HTmpIdentity);
    HOperatorSet.HomMat2dScale(HTmpIdentity, sx, sy, px, py, out HTuple hTmp);
    HOperatorSet.AffineTransImage(DispOrgImg, out HObject tmpImg, hTmp, "constant", "true");

    //画像サイズ取得
    HOperatorSet.GetImageSize(tmpImg, out HTuple wb, out HTuple hb);
    lblRateImgSize.Text = "X:" + wb.D.ToString() + "pixel  Y:" + hb.D.ToString() + "pixel";

    //Zoom方式で表示
    HTuple hwndOrg = hWindowControl1.HalconWindow;
    HOperatorSet.ClearWindow(hwndOrg);
    DispZoom(hwndOrg, tmpImg);
}

冒頭に説明した関数を順番で使用していきます。
AffineTransImage()の第5引数は”true”にしています。
これは、変換後のサイズに合わせて、画像サイズも変化するように設定しています。
これを”false”のままの場合、画像情報だけ拡大縮小され、画像サイズはそのままの状態になります。

拡大時の注意点(基点[不動点]の設定)

基点の設定には注意が必要です。
画像の座標原点は左上が原点です。基点を中心に画像が拡大されるため、基点が(0,0)以外のすうちの場合、マイナス座標に画像情報が行ってしまいます。
マイナス座標になった画像情報は見切れてしまう為、注意が必要です

【基点が(0,0)の場合】

【基点が画像中心の場合】

実行結果

【原点を基点に3倍大きくした時】

【基点を画像中心にして、2倍した時】

見切れている分、画像は小さくなりました。

【Xを1倍、Yを2倍にした時】

まとめ

今回は、画像に倍率をかけて、拡大縮小を行いました。
画像の拡大縮小を行うには、行列の知識があるとスッと理解できそうです。
まぁ無くても、関数の使い方だけ分かっていればOKだと思っています。

hWindowControl内に表示している画像を拡大・縮小したい場合は、プロパティの【ImagePart】を変更する事で画像データは変えずに、表示だけで拡大縮小を行う事は可能です。
作る機会があれば、紹介したいと思います。
コッチの方がユーザーに使ってもらうソフトでは作る価値が高そうです。

補足(作った関数の紹介)

Zoom表示で表示する関数[DispZoom]

private void DispZoom(HTuple windowhandle, HObject img)
{
    //Zoom方式で表示
    HOperatorSet.GetImageSize(img, out HTuple w, out HTuple h);

    double rateR = DEF_H / h, rateC = DEF_W / w;
    double rate = (rateR < rateC) ? rateR : rateC;

    double c1 = -((DEF_W / rate) - w) / 2;
    double c2 = c1 + (DEF_W / rate);
    double r1 = -((DEF_H / rate) - h) / 2;
    double r2 = r1 + (DEF_H / rate);
    HOperatorSet.SetPart(windowhandle, r1, c1, r2, c2);
    HOperatorSet.DispObj(img, windowhandle);
}

画像を選択してもらう関数[SelectImageFile]

private DialogResult SelectImageFile(out string fp)
{
    fp = "";
    OpenFileDialog ofd = new OpenFileDialog();
    ofd.FileName = "";
    ofd.InitialDirectory = @"C:\";
    ofd.Filter = "画像ファイル(*.png;*.jpg)|*.png;*.jpg";
    ofd.Title = "開くファイルを選択してください";

    DialogResult res = ofd.ShowDialog();
    if (res == DialogResult.OK) fp = ofd.FileName;
    return res;
}

【読込】ボタンの処理[btnReadImg_Click]

private void btnReadImg_Click(object sender, EventArgs e)
{
    //初期化
    DispOrgImg = null;
    nudFixedPointX.Value = nudFixedPointX.Minimum;
    nudFixedPointY.Value = nudFixedPointY.Minimum;

    //表示削除
    HTuple hwndOrg = hWindowControl1.HalconWindow;
    HOperatorSet.ClearWindow(hwndOrg);

    //画像を選択してもらう
    if (SelectImageFile(out string fp) == DialogResult.OK)
    {
        //画像読込
        HOperatorSet.ReadImage(out HObject img, fp);
        DispOrgImg = img;

        //最大値を設定
        HOperatorSet.GetImageSize(DispOrgImg, out HTuple wb, out HTuple hb);

        //XYのNumericUpDownの設定
        nudFixedPointX.Maximum = wb.I;
        nudFixedPointY.Maximum = hb.I;

        //サイズ表示
        lblReadImgSize.Text = "X:" + wb.D.ToString() + "pixel  Y:" + hb.D.ToString() + "pixel";

        //Zoom方式で表示
        DispZoom(hwndOrg, img);
    }
}

コメント

タイトルとURLをコピーしました