环境:Win8 64位 Vs2015
Emgu 版本:emgucv-windesktop 3.2.0.2682
示例图上部流程:原图->灰度化->截断阈值化->中值模糊->高斯模糊->膨胀->腐蚀->Ostu二值化。
// 灰度化
Image<Gray, byte> imgGray = new Image<Gray, byte>(imgSrc.Size);
CvInvoke.CvtColor(imgSrc, imgGray, ColorConversion.Bgr2Gray);
//截断阈值化
Image<Gray, byte> imgThresholdTrunc = new Image<Gray, byte>(imgGray.Size);
CvInvoke.Threshold(imgGray, imgThresholdTrunc, 60, 255, ThresholdType.Trunc);
// 中值模糊
Image<Gray, byte> imgMedian = imgThresholdTrunc.SmoothMedian(7); //使用5*5的卷积核
// 高斯模糊
Image<Gray, byte> imgGaussian = imgMedian.SmoothGaussian(5);
// 膨胀,消除杂点
Mat oMat2 = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Rectangle,
new System.Drawing.Size(5, 5), new System.Drawing.Point(0, 0));
Image<Gray, byte> imgErode = new Image<Gray, byte>(imgGray.Size);
CvInvoke.Erode(imgGaussian, imgErode, oMat2, new System.Drawing.Point(0, 0), 4,
BorderType.Default, new MCvScalar(255, 0, 0, 255));
// 腐蚀,消除杂点
Image<Gray, byte> imgDilate = new Image<Gray, byte>(imgGray.Size);
CvInvoke.Dilate(imgErode, imgDilate, oMat2, new System.Drawing.Point(0, 0), 4,
BorderType.Default, new MCvScalar(255, 0, 0, 255));
// Otsu二值化
Image<Gray, byte> imgThresholdOtsu = new Image<Gray, byte>(imgGray.Size);
CvInvoke.Threshold(imgDilate, imgThresholdOtsu, 0, 255, ThresholdType.Otsu);
示例图下部流程:原图->灰度化->截断阈值化->消除裂缝->Ostu二值化->识别Contours->绘制Contours.
// 灰度化
Image<Gray, byte> imgGray = new Image<Gray, byte>(imgSrc.Size);
CvInvoke.CvtColor(imgSrc, imgGray, ColorConversion.Bgr2Gray);
//截断阈值化
Image<Gray, byte> imgThresholdTrunc = new Image<Gray, byte>(imgGray.Size);
CvInvoke.Threshold(imgGray, imgThresholdTrunc, 60, 255, ThresholdType.Trunc);
// 消除裂缝
Mat oMat1 = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Rectangle,
new System.Drawing.Size(6, 6), new System.Drawing.Point(0, 0));
Image<Gray, byte> imgMorphologyEx = new Image<Gray, byte>(imgGray.Size);
CvInvoke.MorphologyEx(imgThresholdTrunc, imgMorphologyEx, Emgu.CV.CvEnum.MorphOp.Close, oMat1,
new System.Drawing.Point(0, 0), 1, BorderType.Default,
new MCvScalar(255, 0, 0, 255));
// Otsu二值化
Image<Gray, byte> imgThresholdOtsu = new Image<Gray, byte>(imgGray.Size);
CvInvoke.Threshold(imgMorphologyEx, imgThresholdOtsu, 0, 255, ThresholdType.Otsu);
List<RotatedRect> boxList = new List<RotatedRect>(); //a box is a rotated rectangle
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(imgThresholdOtsu, contours, null, RetrType.List,
ChainApproxMethod.ChainApproxSimple);
Image<Bgr, byte> imgResult = new Image<Bgr, byte>(imgGray.Size);
CvInvoke.CvtColor(imgThresholdOtsu, imgResult, ColorConversion.Gray2Bgr);
MCvScalar oScaler = new MCvScalar(40, 255, 255, 255);
int count = contours.Size;
for (int i = 0; i < count; i++)
{
using (VectorOfPoint contour = contours[i])
using (VectorOfPoint approxContour = new VectorOfPoint())
{
CvInvoke.ApproxPolyDP(contour, approxContour, CvInvoke.ArcLength(contour, true) * 0.05, true);
double dArea = CvInvoke.ContourArea(approxContour, false);
if (dArea > imgThresholdOtsu.Rows * imgThresholdOtsu.Cols / 3d)
{
if (approxContour.Size == 4)
{
#region determine if all the angles in the contour are within [80, 100] degree
bool isRectangle = true;
System.Drawing.Point[] pts = approxContour.ToArray();
LineSegment2D[] edges = Emgu.CV.PointCollection.PolyLine(pts, true);
for (int j = 0; j < edges.Length; j++)
{
double angle = Math.Abs(
edges[(j + 1) % edges.Length].GetExteriorAngleDegree(edges[j]));
if (angle < 80 || angle > 100)
{
isRectangle = false;
break;
}
}
#endregion
if (isRectangle)
CvInvoke.DrawContours(imgResult, contours, i, oScaler, 3);
}
}
}
}