C#使用OpenCvSharp實現(xiàn)圖像校正
更新時間:2023年11月15日 09:53:48 作者:天天代碼碼天天
這篇文章主要為大家詳細介紹了C#如何使用OpenCvSharp實現(xiàn)圖像校正功能,文中的示例代碼簡潔易懂,具有一定的學(xué)習(xí)價值,需要的小伙伴可以參考下
效果

實現(xiàn)代碼
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using OpenCvSharp;
using OpenCvSharp.Extensions;
namespace OpenCvSharp_圖像校正
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
string img = "test.png";
private void Form1_Load(object sender, EventArgs e)
{
pictureBox1.Image = new Bitmap(img);
}
private void button1_Click(object sender, EventArgs e)
{
Mat src = new Mat(img);
//轉(zhuǎn)化為灰度圖
//Cv2.CvtColor(src, src, ColorConversionCodes.RGB2GRAY);
InputArray kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3));
Cv2.MorphologyEx(src, src, MorphTypes.Close, kernel, new OpenCvSharp.Point(-1, -1), 3);
//Cv2.ImShow("MorphologyEx", src);
/*
ksize,高斯內(nèi)核大小,ksize.width和ksize.height必須是正奇數(shù),兩者可以不相同,值越大越模糊
sigmaX,Y軸方向的標(biāo)準(zhǔn)差,值越大越模糊
sigmaY,X軸方向的標(biāo)準(zhǔn)差,值越大越模糊
*/
Cv2.GaussianBlur(src, src, new OpenCvSharp.Size(11, 11), 2, 2);
//Cv2.ImShow("GaussianBlur", src);
//Canny邊緣檢測
Mat canny_Image = new Mat();
Cv2.Canny(src, canny_Image, 10, 30, 3, false);
OpenCvSharp.Point[][] contours;
HierarchyIndex[] hierarchly;
/*
findContours找到輪廓
第一個參數(shù):單通道圖像矩陣,可以是灰度圖,但更常用的是二值圖像,一般是經(jīng)過Canny、拉普拉斯等邊緣檢測算子處理過的二值圖像;
第二個參數(shù):contours
第三個參數(shù):hierarchy
第四個參數(shù):輪廓的檢索模式
取值一:CV_RETR_EXTERNAL 只檢測最外圍輪廓,包含在外圍輪廓內(nèi)的內(nèi)圍輪廓被忽略
取值二:CV_RETR_LIST 檢測所有的輪廓,包括內(nèi)圍、外圍輪廓,但是檢測到的輪廓不建立等級關(guān)系,彼此之間獨立,沒有等級關(guān)系,這就意味著這個檢索模式下不存在父輪廓或內(nèi)嵌輪廓,所以hierarchy向量內(nèi)所有元素的第3、第4個分量都會被置為-1,具體下文會講到
取值三:CV_RETR_CCOMP 檢測所有的輪廓,但所有輪廓只建立兩個等級關(guān)系,外圍為頂層,若外圍內(nèi)的內(nèi)圍輪廓還包含了其他的輪廓信息,則內(nèi)圍內(nèi)的所有輪廓均歸屬于頂層
取值四:CV_RETR_TREE 檢測所有輪廓,所有輪廓建立一個等級樹結(jié)構(gòu)。外層輪廓包含內(nèi)層輪廓,內(nèi)層輪廓還可以繼續(xù)包含內(nèi)嵌輪廓。
第五個參數(shù):輪廓的近似方法
取值一:CV_CHAIN_APPROX_NONE 保存物體邊界上所有連續(xù)的輪廓點到contours向量內(nèi)
取值二:CV_CHAIN_APPROX_SIMPLE 僅保存輪廓的拐點信息,把所有輪廓拐點處的點保存入contours向量內(nèi),拐點與拐點之間直線段上的信息點不予保留
取值三和四:CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法
第六個參數(shù):Point偏移量,所有的輪廓信息相對于原始圖像對應(yīng)點的偏移量,相當(dāng)于在每一個檢測出的輪廓點上加上該偏移量,且Point可以是負(fù)值。不填為默認(rèn)不偏移Point()
*/
Cv2.FindContours(canny_Image, out contours, out hierarchly,
RetrievalModes.External,
ContourApproximationModes.ApproxSimple,
new OpenCvSharp.Point(0, 0));
if (contours.Length == 0)
{
MessageBox.Show("邊緣檢測失敗");
return;
}
Random rnd = new Random();
Scalar color;
color = new Scalar(0, 255, 0);
for (int i = 0; i < contours.Length; i++)
{
color = new Scalar(rnd.Next(0, 255), rnd.Next(0, 255), rnd.Next(0, 255));
Cv2.DrawContours(src, contours, i, color, 2, LineTypes.Link4);
}
//Cv2.ImShow("contours", src);
//求出面積最大的輪廓
double max_area = 0.0;
double currentArea = 0.0;
OpenCvSharp.Point[] max_contour = null;
for (int i = 0; i < contours.Length; i++)
{
currentArea = Cv2.ContourArea(contours[i]);
if (currentArea > max_area)
{
max_area = currentArea;
max_contour = contours[i];
}
}
//多邊形擬合凸包的四個頂點
OpenCvSharp.Point[] hull = Cv2.ConvexHull(max_contour);
double epsilon = 0.02 * Cv2.ArcLength(max_contour, true);
OpenCvSharp.Point[] approx = Cv2.ApproxPolyDP(hull, epsilon, true);
if (approx.Length != 4)
{
MessageBox.Show("擬合凸包的四個頂點失敗");
return;
}
Scalar scalar2 = new Scalar(0, 255, 255);
Cv2.Line(src, approx[0], approx[1], scalar2, 1, LineTypes.Link4);
Cv2.Line(src, approx[1], approx[2], scalar2, 1, LineTypes.Link4);
Cv2.Line(src, approx[2], approx[3], scalar2, 1, LineTypes.Link4);
Cv2.Line(src, approx[3], approx[0], scalar2, 1, LineTypes.Link4);
//排序
Array.Sort(approx, (cs1, cs2) =>
{
if (cs1 != null && cs1 != null)
{
if (cs1.Y > cs2.Y)
return 1;
else if (cs1.Y == cs2.Y)
{
if (cs1.X < cs2.X)
return 1;
else return -1;
}
else
return -1;
}
return 0;
});
//算法找出的角點
OpenCvSharp.Point2f[] srcPt = new OpenCvSharp.Point2f[4];
srcPt[0] = approx[0];
srcPt[1] = approx[1];
srcPt[2] = approx[3];
srcPt[3] = approx[2];
//最小外接矩形
RotatedRect rect = Cv2.MinAreaRect(srcPt);
Rect box = rect.BoundingRect();
OpenCvSharp.Point2f[] dstPt = new OpenCvSharp.Point2f[4];
dstPt[0].X = box.X;
dstPt[0].Y = box.Y;
dstPt[1].X = box.X + box.Width;
dstPt[1].Y = box.Y;
dstPt[2].X = box.X + box.Width;
dstPt[2].Y = box.Y + box.Height;
dstPt[3].X = box.X;
dstPt[3].Y = box.Y + box.Height;
Mat src2 = new Mat(img);
Mat final = new Mat();
Mat warpmatrix = Cv2.GetPerspectiveTransform(srcPt, dstPt);//獲得變換矩陣
Cv2.WarpPerspective(src2, final, warpmatrix, src.Size());//投射變換,將結(jié)果賦給final
Bitmap temp = BitmapConverter.ToBitmap(final);
pictureBox2.Image = temp;
DrawLine(srcPt, dstPt);
//Application.DoEvents();
//System.Threading.Thread.Sleep(1000);
//pictureBox2.Image = CutImage(temp, (int)p2f[0].X, (int)p2f[0].Y, (int)p2f[2].X, (int)p2f[2].Y);
}
void DrawLine(OpenCvSharp.Point2f[] srcPt, OpenCvSharp.Point2f[] dstPt)
{
Bitmap bmp = new Bitmap(img);
Graphics g = Graphics.FromImage(bmp);
Pen pen = new Pen(Color.Red, 3);
Pen pen2 = new Pen(Color.Blue, 3);
g.DrawLine(pen, srcPt[0].X, srcPt[0].Y, srcPt[1].X, srcPt[1].Y);
g.DrawLine(pen, srcPt[1].X, srcPt[1].Y, srcPt[2].X, srcPt[2].Y);
g.DrawLine(pen, srcPt[2].X, srcPt[2].Y, srcPt[3].X, srcPt[3].Y);
g.DrawLine(pen, srcPt[3].X, srcPt[3].Y, srcPt[0].X, srcPt[0].Y);
g.DrawLine(pen2, dstPt[0].X, dstPt[0].Y, dstPt[1].X, dstPt[1].Y);
g.DrawLine(pen2, dstPt[1].X, dstPt[1].Y, dstPt[2].X, dstPt[2].Y);
g.DrawLine(pen2, dstPt[2].X, dstPt[2].Y, dstPt[3].X, dstPt[3].Y);
g.DrawLine(pen2, dstPt[3].X, dstPt[3].Y, dstPt[0].X, dstPt[0].Y);
pictureBox1.Image = bmp;
}
/// <summary>
/// 剪裁圖片
/// </summary>
/// <param name="src">原圖片</param>
/// <param name="left">左坐標(biāo)</param>
/// <param name="top">頂部坐標(biāo)</param>
/// <param name="right">右坐標(biāo)</param>
/// <param name="bottom">底部坐標(biāo)</param>
/// <returns>剪裁后的圖片</returns>
public Image CutImage(Image src, int left, int top, int right, int bottom)
{
Bitmap srcBitmap = new Bitmap(src);
int width = right - left;
int height = bottom - top;
Bitmap destBitmap = new Bitmap(width, height);
using (Graphics g = Graphics.FromImage(destBitmap))
{
g.Clear(Color.Transparent);
//設(shè)置畫布的描繪質(zhì)量
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.DrawImage(srcBitmap, new Rectangle(0, 0, width, height), left, top, width, height, GraphicsUnit.Pixel);
}
return destBitmap;
}
}
}以上就是C#使用OpenCvSharp實現(xiàn)圖像校正的詳細內(nèi)容,更多關(guān)于C# OpenCvSharp圖像校正的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
.net文件上傳時實現(xiàn)通過文件頭確認(rèn)文件類型的方法
這篇文章主要介紹了.net文件上傳時實現(xiàn)通過文件頭確認(rèn)文件類型的方法,很實用的功能,需要的朋友可以參考下2014-07-07
在C# WPF下自定義滾動條ScrollViewer樣式的操作
這篇文章主要介紹了在C# WPF下自定義滾動條ScrollViewer樣式的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01

