OpenCvSharp手繪ROI區域+模板匹配+霍夫變換檢測圓的邊界
最終效果如下:
左側為檢測圖片、右側為模板,右下角textbox為輪轂中心的畫素座標
操作步驟:
1、點選開啟影像選擇一張比較不錯的圖片,用於畫模板;
2、在picturebox中畫取ROI區域生成模板(有拖拽線不顯示這點小問題);
3、重新選取一張待檢測圖片,點選模板匹配,即可找到ROI區域並把圓的邊界和圓心找到;
完整程式碼如下(部分程式碼還有待改善):
using OpenCvSharp;
using OpenCvSharp.Extensions;
using System;
using System.Linq;
using System.Windows.Forms;
using Point = OpenCvSharp.Point;
using Size = OpenCvSharp.Size;
namespace DrawROI
{
public partial class Form1 : Form
{
private System.Drawing.Point RectStartPoint, tempEndPoint;
bool blnDraw;
Mat ImageROI;
Mat OrgMat;
private string FilePath;
public Form1()
{
InitializeComponent();
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
RectStartPoint = e.Location; //獲得滑鼠按下的pictureBox上座標
Invalidate();
blnDraw = true;//判斷標誌
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (blnDraw)
{
if (e.Button != MouseButtons.Left)//判斷是否按下左鍵
{
return;
}
tempEndPoint = e.Location; //記錄框的位置和大小
//pictureBox上開始點座標
//Rect.Location = new System.Drawing.Point(
//Math.Min(RectStartPoint.X, tempEndPoint.X),
//Math.Min(RectStartPoint.Y, tempEndPoint.Y));
pictureBox上矩形大小
//Rect.Size = new System.Drawing.Size(
//Math.Abs(RectStartPoint.X - tempEndPoint.X),
//Math.Abs(RectStartPoint.Y - tempEndPoint.Y));
pictureBox1.Invalidate();
// 最後點位置
int X0, Y0;
Utilities.ConvertCoordinates(pictureBox1, out X0, out Y0, e.X, e.Y);
//在控制元件中
//textBox1.Text = Convert.ToString("pictureBox最後點座標" + e.X + " ," + e.Y); //pictureBox 上終點座標
//textBox2.Text = Convert.ToString("pictureBox開始點座標" + Rect.X + " ," + Rect.Y); //開始點座標
//textBox3.Text = Convert.ToString("pictureBox的Width" + Rect.Width + " ," + Rect.Height);//大小
//Create ROI 感興趣區域
Utilities.ConvertCoordinates(pictureBox1, out X0, out Y0, RectStartPoint.X, RectStartPoint.Y);
int X1, Y1;
Utilities.ConvertCoordinates(pictureBox1, out X1, out Y1, tempEndPoint.X, tempEndPoint.Y);
//感興趣區域 左上點座標-寬-高
//RealImageRect.Location = new System.Drawing.Point(
// Math.Min(X0, X1),
// Math.Min(Y0, Y1));
//RealImageRect.Size = new System.Drawing.Size(
// Math.Abs(X0 - X1),
// Math.Abs(Y0 - Y1));
//textBox4.Text = "原影像上最後點座標: X:" + X0 + " Y:" + Y0;
//textBox5.Text = "原影像上RealImageRect: X:" + RealImageRect.X + " Y:" + RealImageRect.Y; // 原影像-左上點座標
//textBox6.Text = "原影像上RealImageRectSize: X:" + RealImageRect.Width + " Y:" + RealImageRect.Height; // 原影像-大小
Rect tmp_Rect = new Rect(Math.Min(X0, X1), Math.Min(Y0, Y1), Math.Abs(X0 - X1), Math.Abs(Y0 - Y1));
ImageROI = new Mat(OrgMat, tmp_Rect);//新建一個mat,把roi內的影像載入到裡面去。
//Cv2.ImWrite("4.jpg",ImageROI); //儲存
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
// mouseUp 結束以後 將影像顯示在pictureBox2控制元件中
pictureBox2.Image = ImageROI.ToBitmap();
//***************************************//
blnDraw = false; //結束繪製
}
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.ShowDialog();
FilePath = openFileDialog.FileName;
OrgMat = new Mat(FilePath, ImreadModes.Grayscale);
OrgMat.MedianBlur(3);
pictureBox1.Image = BitmapConverter.ToBitmap(OrgMat);
}
private void button3_Click(object sender, EventArgs e)
{
if (ImageROI == null)
{
MessageBox.Show("請先繪製模板");
return;
}
Mat RoiClone = ImageROI.Clone();
Mat mat3 = new Mat();
//建立result的模板,就是MatchTemplate裡的第三個引數
//mat3.Create(mat1.Cols - mat2.Cols + 1, mat1.Rows - mat2.Rows + 1, MatType.CV_32FC1);
//進行匹配(1母圖,2模版子圖,3返回的result,4匹配模式)
Cv2.MatchTemplate(OrgMat, RoiClone, mat3, TemplateMatchModes.SqDiff);
//對結果進行歸一化(這裡我測試的時候沒有發現有什麼用,但在opencv的書裡有這個操作,應該有什麼神祕加成,這裡也加上)
Cv2.Normalize(mat3, mat3, 1, 0, NormTypes.MinMax, -1);
//double minValue, maxValue;
Point minLocation, maxLocation;
/// 通過函式 minMaxLoc 定位最匹配的位置
/// (這個方法在opencv裡有5個引數,這裡我寫的時候發現在有3個過載,看了下可以直接寫成拿到起始座標就不取最大值和最小值了)
/// minLocation和maxLocation根據匹配呼叫的模式取不同的點
Cv2.MinMaxLoc(mat3, out minLocation, out maxLocation);
Mat OrgMatClone = OrgMat.Clone();
//畫出匹配的矩,
//Cv2.Rectangle(mask, maxLocation, new Point(maxLocation.X + mat2.Cols, maxLocation.Y + mat2.Rows), Scalar.Red, 2);
Cv2.Rectangle(OrgMatClone, minLocation, new Point(minLocation.X + RoiClone.Cols, minLocation.Y + RoiClone.Rows), Scalar.Red, 2);
//Cv2.ImShow("mat1", mat1);
//Cv2.ImShow("mat2", mat2);
//霍夫圓檢測:使用霍夫變換查詢灰度影像中的圓。
/*
* 引數:
* 1:輸入引數: 8位、單通道、灰度輸入影像
* 2:實現方法:目前,唯一的實現方法是HoughCirclesMethod.Gradient
* 3: dp :累加器解析度與影像解析度的反比。預設=1
* 4:minDist: 檢測到的圓的中心之間的最小距離。(最短距離-可以分辨是兩個圓的,否則認為是同心圓- src_gray.rows/8)
* 5:param1: 第一個方法特定的引數。[預設值是100] canny邊緣檢測閾值低
* 6:param2: 第二個方法特定於引數。[預設值是100] 中心點累加器閾值 – 候選圓心
* 7:minRadius: 最小半徑
* 8:maxRadius: 最大半徑
*
*/
CircleSegment[] cs = Cv2.HoughCircles(RoiClone, HoughMethods.Gradient, 1, 80, 70, 100, 100, 200);
for (int i = 0; i < cs.Count(); i++)
{
//畫圓
Cv2.Circle(OrgMatClone, (int)(cs[i].Center.X + minLocation.X), (int)(cs[i].Center.Y + minLocation.Y), (int)cs[i].Radius, new Scalar(0, 0, 255), 2, LineTypes.AntiAlias);
//加強圓心顯示
Cv2.Circle(OrgMatClone, (int)cs[i].Center.X, (int)cs[i].Center.Y, 3, new Scalar(0, 0, 255), 2, LineTypes.AntiAlias);
textBox1.Text = cs[i].Center.X.ToString();
textBox2.Text = cs[i].Center.Y.ToString();
}
//pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
pictureBox1.Image = BitmapConverter.ToBitmap(OrgMatClone);
}
//private void pictureBox1_Paint(object sender, PaintEventArgs e)
//{
// if (blnDraw)
// {
// if (pictureBox1.Image != null)
// {
// if (Rect != null && Rect.Width > 0 && Rect.Height > 0)
// {
// e.Graphics.DrawRectangle(new Pen(Color.Red, 1), Rect);//重新繪製顏色為紅色
// }
// }
// }
//}
public class Utilities
{
//座標轉換
//**************************************
//* 圖片左邊轉換,
//* Input輸入: pictureBox 座標X,Y
//* Output輸出: Image 影像上對應的座標
//**************************************//
public static void ConvertCoordinates(PictureBox pic,
out int X0, out int Y0, int x, int y)
{
int pic_hgt = pic.ClientSize.Height;
int pic_wid = pic.ClientSize.Width;
int img_hgt = pic.Image.Height;
int img_wid = pic.Image.Width;
X0 = x;
Y0 = y;
switch (pic.SizeMode)
{
case PictureBoxSizeMode.AutoSize:
case PictureBoxSizeMode.StretchImage:
X0 = (int)(img_wid * x / (float)pic_wid);
Y0 = (int)(img_hgt * y / (float)pic_hgt);
break;
}
}
}
相關文章
- 霍夫變換檢測圓
- 霍夫檢測圓:霍夫梯度法梯度
- 霍夫變換圓檢測原理及 OpenCV API 應用OpenCVAPI
- 計算機視覺 OpenCV Android | 基本特徵檢測之 霍夫圓檢計算機視覺OpenCVAndroid特徵
- 用霍夫變換&SCNN碼一個車道追蹤器CNN
- Qt5&OpenCV3.2 Canny邊緣檢測+Hough變換QTOpenCV
- 使用Dice loss實現清晰的邊界檢測
- 結合模板匹配與測量的剃鬚刀缺陷檢測
- C++區域性變數的記憶體訪問:小心技巧與安全邊界C++變數記憶體
- 百度地圖繪製多邊形區域地圖
- halcon——缺陷檢測常用方法總結(模板匹配(定位)+差分)
- su: 改變圓的平滑度(邊數)
- 影像的邊緣檢測
- 頻域變換
- 基於人形檢測的劃區域客流統計
- Go 效能提升tips--邊界檢查Go
- 模板匹配
- 騰訊安全推出御界NDR「橫移檢測版」,全面檢測域滲透攻擊
- 小波變換檢測訊號突變點的MATLAB實現Matlab
- 影像邊緣檢測
- 《每週一點canvas動畫》——邊界檢測與摩擦力(1)Canvas動畫
- matlab 繪製置信範圍_fill(繪製其區間形成的區域)Matlab
- 如何實現css漸變圓角邊框CSS
- 【WPF】 問題總結-RaidButton修改樣式模板後作用區域的變化AI
- 區域性靜態變數的初始化觀測變數
- 戲說領域驅動設計(八)——邊界
- 模板匹配(matlab)Matlab
- 深入學習OpenCV檢測及分割影象的目標區域OpenCV
- 黑盒測試方法之邊界值分析
- 小波變換與傅立葉變換的區別
- 《超越邊界》
- 3. OpenCV-Python——影像梯度演算法、邊緣檢測、影像金字塔與輪廓檢測、直方圖與傅立葉變換OpenCVPython梯度演算法直方圖
- QTableView表格控制元件區域選擇-自繪選擇區域QTView控制元件
- 3.Canny邊緣檢測
- 二分查詢左邊界,右邊界,>=,>,<=,<
- javascript中的作用域(全域性變數和區域性變數)JavaScript變數
- echarts 繪製圓形進度條帶漸變色Echarts
- 傅立葉變換頻域時域分析