实例介绍
【实例简介】
【实例截图】
【核心代码】
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
//using System.Numerics;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using Point = OpenCvSharp.Point;
using Rect = OpenCvSharp.Rect;
using Size = OpenCvSharp.Size;
namespace RotateTemplate
{
public partial class bn_EasyTmpMaching : Form
{
public bn_EasyTmpMaching()
{
InitializeComponent();
CreatTimer();
}
private System.Drawing.Point RectStartPoint, tempEndPoint;
bool blnDraw;//画ROI的开关
Mat srcImg, roiImg;
Mat roiCopy;
Mat editImg;
//Mat imgRGB = new Mat();
int _index = 0;
string FilePath;
string[] _files;
#region 定时器
Timer _myTimer = new Timer();
private void CreatTimer()
{
_myTimer.Tick = new EventHandler(OnTimer);
_myTimer.Interval = 500;
}
private void OnTimer(object sender, EventArgs e)
{
_myTimer.Stop();
if (_index == 0)
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Multiselect = true;
if (dlg.ShowDialog() == DialogResult.OK)
{
_files = dlg.FileNames;
}
}
FilePath = _files[_index];
Mat tmp = new Mat(FilePath, ImreadModes.Grayscale);
int filecount = _files.GetLength(0);
_index ;
if (_index >= filecount)
{
DialogResult result = MessageBox.Show("是否继续检测?", "询问", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.No)
{
_myTimer.Stop();
return;
}
_index = 0;
}
CircleMatchNcc(tmp, roiImg, 0, 360, 1, 0, 5, TemplateMachingMethod);
_myTimer.Start();
}
#endregion
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; //记录框的位置和大小
pb_src.Invalidate();
// 最后点位置
int X0, Y0;
Utilities.ConvertCoordinates(pb_src, out X0, out Y0, e.X, e.Y);
//Create ROI 感兴趣区域
Utilities.ConvertCoordinates(pb_src, out X0, out Y0, RectStartPoint.X, RectStartPoint.Y);
int X1, Y1;
Utilities.ConvertCoordinates(pb_src, out X1, out Y1, tempEndPoint.X, tempEndPoint.Y);
Rect tmp_Rect = new Rect(Math.Min(X0, X1), Math.Min(Y0, Y1), Math.Abs(X0 - X1), Math.Abs(Y0 - Y1));
roiImg = new Mat(srcImg, tmp_Rect);
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
/*
//System.Numerics.Vector<System.Numerics.Vector<Point>> coutours = new System.Numerics.Vector<System.Numerics.Vector<Point>>();
//System.Numerics.Vector<Vec4i> hierarchy;
HierarchyIndex[] hierarchy;
OpenCvSharp.Point[][] coutours;
Mat imageCountour = new Mat(roiImg.Size(), MatType.CV_8UC1);
Cv2.FindContours(roiImg,out coutours,out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxNone, null);
for(int i=0;i< coutours.Length; i )
{
Cv2.DrawContours(imageCountour, coutours, i,new Scalar(255), 1, LineTypes.Link8, hierarchy);
}
roiImg = imageCountour;
*/
/*
Mat tmp = new Mat();
Mat mask = Mat.Zeros(roiImg.Size(), MatType.CV_8U);
//CircleSegment[] cs = Cv2.HoughCircles(roiImg, HoughMethods.Gradient, 1, 80, 70, 100, 100, 200);
//Cv2.Circle(mask, (int)(cs[0].Center.X), (int)(cs[0].Center.Y), (int)cs[0].Radius, new Scalar(255), 2, LineTypes.AntiAlias);
//Cv2.Normalize(roiImg, roiImg, 1, 0, NormTypes.MinMax, -1);
//Cv2.MinMaxLoc(roiImg, out minLocation, out maxLocation);
Point seed;
//seed.X = (int)cs[0].Center.X; seed.Y = (int)cs[0].Center.Y;
//Cv2.FloodFill(mask, seed, new Scalar(255));
roiImg.CopyTo(tmp, mask);
//roiImg = tmp;
DisplayImgOnPictureBox(roiImg, 2);
HierarchyIndex[] hierarchy;
OpenCvSharp.Point[][] coutours;
Cv2.FindContours(tmp, out coutours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxNone);
//OpenCvSharp.Rect rect = Cv2.BoundingRect(coutours[0]);
//Mat domainRoi = new Mat(tmp, rect);
// roiImg = domainRoi;
Cv2.Normalize(roiImg, roiImg, 1, 0, NormTypes.MinMax, -1);
roiImg = roiImg * 255;
//定义结构元素
InputArray kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5), new Point(-1, -1));
Cv2.MorphologyEx(roiImg, roiImg, MorphTypes.Close, kernel, new Point(-1, -1), 1, BorderTypes.Constant, Scalar.Red);
Cv2.MorphologyEx(roiImg, roiImg, MorphTypes.Gradient, kernel, new Point(-1, -1), 1, BorderTypes.Constant, Scalar.Red);
*/
Mat tmp = new Mat ();
roiImg.CopyTo(tmp);
Cv2.Canny(roiImg, tmp, 10, 200);
// mouseUp 结束以后 将图像显示在pictureBox2控件中
DisplayImgOnPictureBox(tmp, 1);
//***************************************//
blnDraw = false; //结束绘制
}
private void bn_OpenImg_Click(object sender, EventArgs e)
{
OpenFileDialog imgDlgPath = new OpenFileDialog();
imgDlgPath.ShowDialog();
FilePath = imgDlgPath.FileName;
srcImg = new Mat(FilePath, ImreadModes.Grayscale);
/*
int height = srcImg.Rows;
int width = srcImg.Cols;
int cn = srcImg.Channels(); //通道数
float alpha = 1.2f; //系数
float beta = 60f; //增益
Vec2b color1 = new Vec2b();
for (int i = 0; i < height; i )
{
for (int j = 0; j < height; j )
{
color1.Item0 = (byte)((srcImg.Get<Vec2b>(i, j).Item0 45));
color1.Item1 = (byte)((srcImg.Get<Vec2b>(i, j).Item1 45));
srcImg.Set(i, j, color1);
}
}
*/
DisplayImgOnPictureBox(srcImg, 0);
}
int Blur = 3;
private void bn_MedianBlur_Click(object sender, EventArgs e)
{
srcImg.MedianBlur(Blur);
DisplayImgOnPictureBox(srcImg, 0);
}
private void comboBox_Load()
{
comboBox_Blur.Items.Add("0");
comboBox_Blur.Items.Add("1");
comboBox_Blur.Items.Add("2");
comboBox_Blur.Items.Add("3");
comboBox_Blur.Items.Add("4");
comboBox_Blur.Items.Add("5");
comboBox_TemplateMatchModes.Items.Add("平方差");
comboBox_TemplateMatchModes.Items.Add("归一化的平方差");
comboBox_TemplateMatchModes.Items.Add("相关性匹配");
comboBox_TemplateMatchModes.Items.Add("归一化的相关性匹配");
comboBox_TemplateMatchModes.Items.Add("相关性系数匹配");
comboBox_TemplateMatchModes.Items.Add("归一化的相关性系数匹配");
}
private void comboBox_Blur_SelectedIndexChanged(object sender, EventArgs e)
{
switch (comboBox_Blur.SelectedItem.ToString()) //获取选择的内容
{
case "0": Blur = 1; break;
case "1": Blur = 1; break;
case "2": Blur = 2; break;
case "3": Blur = 3; break;
case "4": Blur = 4; break;
case "5": Blur = 5; break;
}
}
public int TemplateMachingMethod = 0;
private void comboBox_TemplateMatchModes_SelectedIndexChanged(object sender, EventArgs e)
{
switch (comboBox_TemplateMatchModes.SelectedItem.ToString()) //获取选择的内容
{
case "平方差": TemplateMachingMethod = 1; break;
case "归一化的平方差": TemplateMachingMethod = 2; break;
case "相关性匹配": TemplateMachingMethod = 3; break;
case "归一化的相关性匹配": TemplateMachingMethod = 4; break;
case "相关性系数匹配": TemplateMachingMethod = 5; break;
case "归一化的相关性系数匹配": TemplateMachingMethod = 6; break;
}
}
private void Form1_Load(object sender, EventArgs e)
{
comboBox_Load();
}
private void bn_easyTmpM_Click(object sender, EventArgs e)
{
if (srcImg == null)
{
MessageBox.Show("请先绘制模板");
return;
}
Mat roiClone = roiImg.Clone();
Mat result = 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(srcImg, roiClone, result, TemplateMatchModes.SqDiff);
//对结果进行归一化(这里我测试的时候没有发现有什么用,但在opencv的书里有这个操作,应该有什么神秘加成,这里也加上)
Cv2.Normalize(result, result, 1, 0, NormTypes.MinMax, -1);
//double minValue, maxValue;
Point minLocation, maxLocation;
/// 通过函数 minMaxLoc 定位最匹配的位置
/// (这个方法在opencv里有5个参数,这里我写的时候发现在有3个重载,看了下可以直接写成拿到起始坐标就不取最大值和最小值了)
/// minLocation和maxLocation根据匹配调用的模式取不同的点
Cv2.MinMaxLoc(result, out minLocation, out maxLocation);
Mat OrgMatClone = srcImg.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);
//霍夫圆检测:使用霍夫变换查找灰度图像中的圆。
/*
* 参数:
* 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);
Mat mask = Mat.Zeros(OrgMatClone.Size(), MatType.CV_8U);
for (int i = 0; i < cs.Count(); i )
{
//画圆
Cv2.Circle(mask, (int)(cs[i].Center.X minLocation.X), (int)(cs[i].Center.Y minLocation.Y), (int)cs[i].Radius, new Scalar(255, 0, 255), 2, LineTypes.AntiAlias);
//加强圆心显示
//Cv2.Circle(mask, (int)cs[i].Center.X, (int)cs[i].Center.Y, 3, new Scalar(255, 0, 255), 2, LineTypes.AntiAlias);
txt_resX.Text = (cs[i].Center.X minLocation.X).ToString("0.000");
txt_resY.Text = (cs[i].Center.Y minLocation.Y).ToString("0.000");
txt_resAngle.Text = ("——"); txt_resScore.Text = ("——");
}
Point seed;
seed.X = (int)(cs[0].Center.X minLocation.X); seed.Y = (int)(cs[0].Center.Y minLocation.Y);
//Mat filledArea = new Mat(srcImg.Rows, srcImg.Cols,MatType.CV_8UC1);
//Rect filledArea;
//Cv2.FloodFill(mask, seed, new Scalar(254,10,254),out filledArea, Scalar.All(0), Scalar.All(0), FloodFillFlags.FixedRange);
//Point elseSeed;
//elseSeed.X = 1; elseSeed.Y = 1;
Cv2.FloodFill(mask, seed, new Scalar(255));
editImg = new Mat();
//srcImg.CopyTo(tmp);
srcImg.CopyTo(editImg, mask);
DisplayImgOnPictureBox(editImg, 0);
}
private void bn_contourDet_Click(object sender, EventArgs e)
{
roiCopy = new Mat();
roiImg.CopyTo(roiCopy);
Cv2.Threshold(roiCopy, roiCopy, 127, 255, ThresholdTypes.Binary);
HierarchyIndex[] hierarchy;
OpenCvSharp.Point[][] coutours;
// 形态学操作
Mat kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3), new OpenCvSharp.Point(-1, -1));
// 构建形态学操作的结构元
//morphologyEx(binary_img, binary_img, MORPH_CLOSE, kernel, Point(-1, -1));
Cv2.MorphologyEx(roiCopy, roiCopy, MorphTypes.Close, kernel, new OpenCvSharp.Point(-1, -1));
//闭操作
kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3), new OpenCvSharp.Point(-1, -1));
// 构建形态学操作的结构元
Cv2.MorphologyEx(roiCopy, roiCopy, MorphTypes.Open, kernel, new OpenCvSharp.Point(-1, -1));
Cv2.FindContours(roiCopy, out coutours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxNone);
DisplayImgOnPictureBox(roiCopy, 2);
}
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;
}
}
}
private void DisplayImgOnPictureBox(Mat img, int pbIndex)
{
//pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
switch (pbIndex)
{
case 0:
pb_src.Image = img.ToBitmap();
break;
case 1:
pb_roi.Image = img.ToBitmap();
break;
case 2:
pb_contourRoi.Image = img.ToBitmap();
break;
}
}
//********************************************************************************************************************************
private void bn_rotateTmpM_Click(object sender, EventArgs e)
{
/*
Mat tmp = new Mat();
srcImg.CopyTo(tmp);
Cv2.Threshold(tmp, tmp, 127, 255, ThresholdTypes.Binary);
HierarchyIndex[] hierarchy;
OpenCvSharp.Point[][] coutours;
// 形态学操作
Mat kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3), new OpenCvSharp.Point(-1, -1));
// 构建形态学操作的结构元
//morphologyEx(binary_img, binary_img, MORPH_CLOSE, kernel, Point(-1, -1));
Cv2.MorphologyEx(tmp, tmp, MorphTypes.Close, kernel, new OpenCvSharp.Point(-1, -1));
//闭操作
kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(3, 3), new OpenCvSharp.Point(-1, -1));
// 构建形态学操作的结构元
Cv2.MorphologyEx(tmp, tmp, MorphTypes.Open, kernel, new OpenCvSharp.Point(-1, -1));
Cv2.FindContours(tmp, out coutours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxNone);
*/
Mat tmpSrc = new Mat();
srcImg.MedianBlur(Blur);
srcImg.CopyTo(tmpSrc);
/*
Cv2.Normalize(tmpSrc, tmpSrc, 1, 0, NormTypes.MinMax, -1);
tmpSrc = tmpSrc * 255;
*/
//定义结构元素
InputArray kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3), new Point(-1, -1));
Cv2.MorphologyEx(tmpSrc, tmpSrc, MorphTypes.Open, kernel, new Point(-1, -1), 1, BorderTypes.Constant, Scalar.Red);
Cv2.MorphologyEx(tmpSrc, tmpSrc, MorphTypes.Gradient, kernel, new Point(-1, -1), 1, BorderTypes.Constant, Scalar.Red);
DisplayImgOnPictureBox(tmpSrc, 0);
CircleMatchNcc(tmpSrc, roiImg, 0, 360, 1, 0, 5, TemplateMachingMethod);
}
private void bn_Canny_Click(object sender, EventArgs e)
{
roiCopy = new Mat();
roiImg.CopyTo(roiCopy);
Cv2.Canny(srcImg, srcImg, 100, 255, 3, true);
Cv2.Canny(roiImg, roiImg, 100, 255, 3, true);
DisplayImgOnPictureBox(srcImg, 0);
DisplayImgOnPictureBox(roiImg, 2);
}
private void bn_openOperation_Click(object sender, EventArgs e)
{
Cv2.Normalize(srcImg, srcImg, 1, 0, NormTypes.MinMax, -1);
srcImg = srcImg * 255;
//:定义结构元素
InputArray kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3), new Point(-1, -1));
//开操作,也可省落变量前缀名
Cv2.MorphologyEx(srcImg, srcImg, MorphTypes.Gradient, kernel, new Point(-1, -1), 1, BorderTypes.Constant, Scalar.Gold);
DisplayImgOnPictureBox(srcImg, 0);
}
private void bn_autoMatching_Click(object sender, EventArgs e)
{
_index = 0;
_myTimer.Start();
}
private double[] CircleMatchNcc(Mat srcImage, Mat modelImage, double angleStart, double angleRange, double angleStep, int numLevels, double thresScore, int nccMethod)
{
double step = angleRange / ((angleRange / angleStep) / 100);
double start = angleStart;
double range = angleRange;
double[] ResultPoint;
Mat result, src, model;
try
{
//定义图片匹配所需要的参数
int resultCols = srcImage.Cols - modelImage.Cols 1;
int resultRows = srcImage.Rows - modelImage.Cols 1;
result = new Mat(resultCols, resultRows, MatType.CV_8U);
src = new Mat();
model = new Mat();
srcImage.CopyTo(src);
modelImage.CopyTo(model);
}
catch
{
ResultPoint = new double[4];
return ResultPoint;
}
//对模板图像和待检测图像分别进行图像金字塔下采样
for (int i = 0; i < numLevels; i )
{
Cv2.PyrDown(src, src, new Size(src.Cols / 2, src.Rows / 2));
Cv2.PyrDown(model, model, new Size(model.Cols / 2, model.Rows / 2));
}
TemplateMatchModes matchMode = TemplateMatchModes.CCoeffNormed;
switch (nccMethod)
{
case 0:
//该方法使用平方差进行匹配,因此最佳的匹配结果在结果为0处,值越大匹配结果越差。
matchMode = TemplateMatchModes.SqDiff;
break;
case 1:
//该方法使用归一化的平方差进行匹配,最佳匹配也在结果为0处。
matchMode = TemplateMatchModes.SqDiffNormed;
break;
case 2:
//相关性匹配方法,该方法使用源图像与模板图像的卷积结果进行匹配,因此,最佳匹配位置在值最大处,值越小匹配结果越差。
matchMode = TemplateMatchModes.CCorr;
break;
case 3:
//归一化的相关性匹配方法,与相关性匹配方法类似,最佳匹配位置也是在值最大处。
matchMode = TemplateMatchModes.CCorrNormed;
break;
case 4:
//相关性系数匹配方法,该方法使用源图像与其均值的差、模板与其均值的差二者之间的相关性进行匹配,最佳匹配结果在值等于1处,最差匹配结果在值等于-1处,值等于0直接表示二者不相关。
matchMode = TemplateMatchModes.CCoeff;
break;
case 5:
//归一化的相关性系数匹配方法,正值表示匹配的结果较好,负值则表示匹配的效果较差,也是值越大,匹配效果也好。
matchMode = TemplateMatchModes.CCoeffNormed;
break;
}
//在没有旋转的情况下进行第一次匹配
Cv2.MatchTemplate(src, model, result, matchMode);
Cv2.MinMaxLoc(result, out double minVal, out double maxVal, out OpenCvSharp.Point minLoc, out OpenCvSharp.Point maxLoc, new Mat());
OpenCvSharp.Point location = maxLoc;
double temp = maxVal;
double angle = 0;
OpenCvSharp.Point minloc, maxloc;
Mat newImg;
//OpenCvSharp.Point minloc, maxloc;
//以最佳匹配点左右十倍角度步长进行循环匹配,直到角度步长小于参数角度步长
if (nccMethod == 0 || nccMethod == 1)
{
do
{
for (int i = 0; i <= (int)range / step; i )
{
newImg = ImageRotate(model, start step * i);
Cv2.MatchTemplate(src, newImg, result, matchMode);
//Cv2.Normalize(result, result, 1, 0, NormTypes.MinMax, -1);
Cv2.MinMaxLoc(result, out double minval, out double maxval, out minloc, out maxloc, new Mat());
if (maxval < temp)
{
location = maxloc;
temp = maxval;
angle = start step * i;
}
if (i >= (int)range / step)
Cv2.Rectangle(src, minloc, new Point(minloc.X modelImage.Cols, minloc.Y modelImage.Rows), Scalar.White, 2);
}
DisplayImgOnPictureBox(src, 0);
range = step * 2;
start = angle - step;
step = step / 10;
} while (step > angleStep);
ResultPoint = new double[] { location.X * Math.Pow(2, numLevels) modelImage.Width / 2, location.Y * Math.Pow(2, numLevels) modelImage.Height / 2, -angle, temp };
return ResultPoint;
}
else
{
do
{
for (int i = 0; i <= (int)range / step; i )
{
newImg = ImageRotate(model, start step * i);
Cv2.MatchTemplate(src, newImg, result, matchMode);
Cv2.MinMaxLoc(result, out double minval, out double maxval, out minloc, out maxloc, new Mat());
if (maxval > temp)
{
location = maxloc;
temp = maxval;
angle = start step * i;
}
if (i >= (int)range / step)
Cv2.Rectangle(src, minloc, new Point(minloc.X modelImage.Cols, minloc.Y modelImage.Rows), Scalar.White, 2);
}
range = step * 2;
start = angle - step;
step = step / 10;
DisplayImgOnPictureBox(src, 0);
} while (step > angleStep);
if (temp > thresScore)
{
ResultPoint = new double[] { location.X * Math.Pow(2, numLevels), location.Y * Math.Pow(2, numLevels), -angle, temp };
return ResultPoint;
}
}
ResultPoint = new double[4];
return ResultPoint;
}
/// <summary>
/// 图像旋转
/// </summary>
/// <param name="image">输入图像</param>
/// <param name="angle">旋转的角度</param>
/// <returns>旋转后图像</returns>
static Mat ImageRotate(Mat image, double angle)
{
Mat newImg = new Mat();
Point2f pt = new Point2f((float)image.Cols / 2, (float)image.Rows / 2);
Mat r = Cv2.GetRotationMatrix2D(pt, angle, 1.0);
Cv2.WarpAffine(image, newImg, r, image.Size());
return newImg;
}
}
}
好例子网口号:伸出你的我的手 — 分享!
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明


网友评论
我要评论