Halcon hWindowControl 鼠標縮放平移區域模板匹配繪製

如題所示標題,想同時表達兩個意思:1:縮放平移繪製區域,2:創建模板匹配區域並保存。被一個技術問題卡住折騰了近大半天時間+熬夜2個小時,經過不懈努力,反覆驗證各參數意義,找到了問題的原因,終於攻克難題。分享給需要的朋友。效果如下:

思路如下:

首先鼠標滾輪縮放,按壓鼠標左鍵平移的鼠標事件組合:MouseDown,MouseUp,MouseMove,MouseWheelEvent,

具體爲:

void AddEvent()
        {
            hWindowControl2.HMouseWheel += HWindowControl1_HMouseWheel;
            hWindowControl2.HMouseMove += HWindowControl1_HMouseMove;
            hWindowControl2.HMouseDown += HWindowControl1_HMouseDown;
            hWindowControl2.HMouseUp += HWindowControl1_HMouseUp;
            hWindowControl2.MouseLeave += HWindowControl1_MouseLeave;
        }

MouseDown記錄鼠標點擊的起始位置:

 bool mousePressed = false;
        Point startPoint = Point.Empty;

        private void HWindowControl1_HMouseDown(object sender, HMouseEventArgs e)
        {
            mousePressed = true;
            startPoint = new Point((int)e.X, (int)e.Y);
            this.hWindowControl1.Cursor = Cursors.SizeAll;
        }

MouseMove 平移:注意關鍵之處,每次移動後的步進位置,需要重新給startPoint賦值,此處調試一下代碼就知道如何寫了。

另外一點是每次平移後把最新的平移旋轉矩陣 out 參數出來,供下次作爲新參數傳遞進去重新計算;

 private void HWindowControl1_HMouseMove(object sender, HMouseEventArgs e)
        {

            if (hMatrix == null || !mousePressed) return;

            HTuple hv_Matrix = null;
            double x = e.X - startPoint.X;
            double y = e.Y - startPoint.Y;
            ImageHandle.MoveImage(h_Image, out h_ScaledImage, hWindow, hMatrix, out hv_Matrix, y, x);
            startPoint = new Point((int)e.X, (int)e.Y);
            hMatrix = hv_Matrix;
        }

鼠標離開控件區域:防止bug發生; 

private void HWindowControl1_MouseLeave(object sender, EventArgs e)
        {
            mousePressed = false;
            startPoint = Point.Empty;
            this.hWindowControl1.Cursor = Cursors.Default;
        }

MoseUp結束移動:

 private void HWindowControl1_HMouseUp(object sender, HMouseEventArgs e)
        {
            mousePressed = false;
            startPoint = Point.Empty;
            this.hWindowControl1.Cursor = Cursors.Default;
        }

鼠標滾輪事件: 

double _scaleValue = 1;
        HTuple hMatrix;
        //HTuple hScaleMatrix;
        private void HWindowControl1_HMouseWheel(object sender, HMouseEventArgs e)
        {
            if (e.Delta == 0) return;
            //獲取鼠標在縮放之前的目標上的位置
            //Point targetZoomFocus1 = e.GetPosition(this.hWindowControl1);

            double d = e.Delta / Math.Abs(e.Delta);
            if (_scaleValue < 0.5 && d < 0) return;
            if (_scaleValue > 5 && d > 0) return;

            double targetScaleValue = 0;
            _scaleValue += d * 0.2;
            HTuple hv_Matrix = null;
            if (d > 0)
            {
                targetScaleValue = 1 + 0.2;
            }
            else
            {
                targetScaleValue = 1 - 0.2;
            }
            ImageHandle.ScaleImage(h_Image, out h_ScaledImage, hWindow, hMatrix, out hv_Matrix, targetScaleValue, e.X, e.Y);
            hMatrix = hv_Matrix;
        }

 

 技術卡殼的地方在於:模板區域的選定後保存繪製結果

 繪製區域:這個沒有什麼可說的,用Halcon導出的C#代碼就可以實現:

 public static void DrawRegion(HObject ho_Image, HWindow hWindow, out HTuple row1, out HTuple col1, out HTuple row2, out HTuple col2)
        {
            HObject ho_ROI_0;
            HOperatorSet.GenEmptyObj(out ho_ROI_0);
            HOperatorSet.SetColor(hWindow, "green");
            HOperatorSet.DrawRectangle1(hWindow, out row1, out col1, out row2, out col2);
            HOperatorSet.GenRectangle1(out ho_ROI_0, row1, col1, row2, col2);
            HOperatorSet.DispObj(ho_ROI_0, hWindow);
            ho_ROI_0.Dispose();
        }

關鍵問題來了:在平移縮放後的圖像上繪製的區域Region所得出的row1,column1,row2,column2 是基於Halcon的標準座標系,而縮放使用的仿射變換,座標系不同了。

使用hom_mat2d_translate_local未果:換個思路,把基於Haclon的座標Region 逆向變換,縮放平移回去就可以了。這個思路也是碰壁後得到的,思路對了,看實現。說來容易,可實際碰壁不少,首先就是使用錯誤導致懷疑Halcon當前版本是否有bug.(最後看來是對算子理解不充分)

例如開始的代碼是這樣寫的:

 //把圖片變回去 hom_mat2d_to_affine_par(HomMat2DTranslate, Sx, Sy, Phi, Theta, Tx, Ty)
            //HTuple hv_Sx = null, hv_Sy = null;
            //HTuple hv_Phi = null, hv_Theta = null, hv_Tx = null, hv_Ty = null;
            //HOperatorSet.HomMat2dToAffinePar(hMatrix, out hv_Sx, out hv_Sy,out hv_Phi, out hv_Theta, out hv_Tx, out hv_Ty);
            //HOperatorSet.VectorAngleToRigid(1/ hv_Sx, 1/ hv_Sy, hv_Phi, hv_Ty, hv_Tx, hv_Phi, out hv_HomMat2D);
            //HOperatorSet.AffineTransImage(ho_TemplateImage, out ho_ImageAffineTrans, hv_HomMat2D, "bicubic", "false");

另外犯了一個錯,就是把二維矩陣變換的:平移和縮放的疊加寫錯:

 HOperatorSet.VectorAngleToRigid()等錯誤運用;

  HOperatorSet.HomMat2dRotate() 試圖先得到一個平移矩形在利用這個算子添加一個縮放矩陣,結果出錯。

而是應該先得到平移矩陣:

  HOperatorSet.VectorAngleToRigid(0, 0, 0, -hv_Tx, -hv_Ty, 0, out hv_HomMat2D);

再得到旋轉矩陣:

HOperatorSet.HomMat2dScale(hv_HomMat2DIdentity, 1 / hv_Sx, 1 / hv_Sy, 0, 0, out hv_HomMat2D_Region);

最後把2者合併:

   HOperatorSet.HomMat2dCompose(hv_HomMat2D_Region, hv_HomMat2D, out hv_targetMatrix); //多謝這個算子

另外一個關鍵算子:

HOperatorSet.HomMat2dToAffinePar(hMatrix, out hv_Sx, out hv_Sy, out hv_Phi, out hv_Theta, out hv_Tx, out hv_Ty);

它可以把Matix分解得到M11,M12,縮放和平移的矢量值;

保存繪製區域模板的完整代碼:

  public static void SaveModel(HObject ho_Image, HWindow hWindow, HTuple hMatrix, HTuple row1, HTuple col1, HTuple row2, HTuple col2, HTuple modelPath)
        {

            // Local iconic variables 

            HObject ho_ROI_0, ho_TemplateImage, ho_ROI_1;
            HTuple hv_ModelID = null;
            HTuple hv_HomMat2D = null;
            HOperatorSet.GenEmptyObj(out ho_ROI_0);
            HOperatorSet.GenEmptyObj(out ho_ROI_1);
            HOperatorSet.GenEmptyObj(out ho_TemplateImage);
            HTuple hv_targetMatrix = null;
            HTuple hv_HomMat2D_Region = null;
            ho_TemplateImage.Dispose();
            ho_ROI_0.Dispose();

            HOperatorSet.GenRectangle1(out ho_ROI_0, row1, col1, row2, col2);

            HTuple hv_Sx = null, hv_Sy = null;
            HTuple hv_Phi = null, hv_Theta = null, hv_Tx = null, hv_Ty = null;
            HOperatorSet.HomMat2dToAffinePar(hMatrix, out hv_Sx, out hv_Sy, out hv_Phi, out hv_Theta, out hv_Tx, out hv_Ty);
            HTuple hv_HomMat2DIdentity = null;
            HOperatorSet.HomMat2dIdentity(out hv_HomMat2DIdentity);
            HOperatorSet.VectorAngleToRigid(0, 0, 0, -hv_Tx, -hv_Ty, 0, out hv_HomMat2D);
            //把圖片變回去
            HOperatorSet.HomMat2dScale(hv_HomMat2DIdentity, 1 / hv_Sx, 1 / hv_Sy, 0, 0, out hv_HomMat2D_Region);
            HOperatorSet.HomMat2dCompose(hv_HomMat2D_Region, hv_HomMat2D, out hv_targetMatrix);
            HOperatorSet.AffineTransRegion(ho_ROI_0, out ho_ROI_1, hv_targetMatrix, "nearest_neighbor");
            HOperatorSet.ReduceDomain(ho_Image, ho_ROI_1, out ho_TemplateImage);
            HOperatorSet.ClearWindow(hWindow);
            HOperatorSet.DispObj(ho_TemplateImage, hWindow);
         
            HOperatorSet.CreateShapeModel(ho_TemplateImage, 5, (new HTuple(0)).TupleRad()
                , (new HTuple(360)).TupleRad(), (new HTuple(0.1406)).TupleRad(), (new HTuple("point_reduction_high")).TupleConcat(
                "no_pregeneration"), "use_polarity", ((new HTuple(48)).TupleConcat(60)).TupleConcat(
                9), 3, out hv_ModelID);

            HOperatorSet.WriteShapeModel(hv_ModelID, modelPath);
            ho_Image.Dispose();

            //ho_ROI_0.Dispose();
            //ho_TemplateImage.Dispose();

        }

2020年3月13日19:43:33

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章