Skip to content
切换导航条
切换导航条
当前项目
正在载入...
登录
孙克
/
ReelCounter
转到一个项目
切换导航栏
切换导航栏固定状态
项目
群组
代码片段
帮助
项目
活动
版本库
流水线
图表
问题
0
合并请求
0
维基
网络
创建新的问题
作业
提交
问题看板
文件
提交
网络
比较
分支
标签
Commit 8511f266
由
SK
编写于
2019-04-12 09:58:21 +0800
浏览文件
选项
浏览文件
标签
下载
电子邮件补丁
差异文件
距离变换找圆法和与料盘中心距离相结合统计数量,
1 个父辈
2671fba1
显示空白字符变更
内嵌
并排
正在显示
5 个修改的文件
包含
639 行增加
和
343 行删除
AccImage/AccImage.csproj
AccImage/ImageUtil.cs
AccImage/SplitItem.cs
Demo/MainForm.cs
Demo/MainForm.designer.cs
AccImage/AccImage.csproj
查看文件 @
8511f26
...
@@ -64,6 +64,7 @@
...
@@ -64,6 +64,7 @@
<ItemGroup>
<ItemGroup>
<Compile Include="ImageUtil.cs" />
<Compile Include="ImageUtil.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SplitItem.cs" />
</ItemGroup>
</ItemGroup>
<ItemGroup>
<ItemGroup>
<Content Include="FodyWeavers.xml" />
<Content Include="FodyWeavers.xml" />
...
...
AccImage/ImageUtil.cs
查看文件 @
8511f26
using
OpenCvSharp
;
using
AccImage
;
using
OpenCvSharp
;
using
OpenCvSharp.Blob
;
using
OpenCvSharp.Blob
;
using
OpenCvSharp.Extensions
;
using
OpenCvSharp.Extensions
;
using
System
;
using
System
;
...
@@ -12,9 +13,6 @@ namespace Acc.Img
...
@@ -12,9 +13,6 @@ namespace Acc.Img
{
{
public
class
ImageUtil
public
class
ImageUtil
{
{
public
static
bool
selectB
=
false
;
public
static
bool
pngB
=
false
;
/// <summary>
/// <summary>
/// 读取图片,,支持格式*.raw,*.bmp;*.gif;*.jpg;*.png
/// 读取图片,,支持格式*.raw,*.bmp;*.gif;*.jpg;*.png
/// </summary>
/// </summary>
...
@@ -27,7 +25,6 @@ namespace Acc.Img
...
@@ -27,7 +25,6 @@ namespace Acc.Img
{
{
if
(
imagePath
.
ToLower
().
EndsWith
(
".raw"
))
if
(
imagePath
.
ToLower
().
EndsWith
(
".raw"
))
{
{
pngB
=
false
;
byte
[]
src
=
System
.
IO
.
File
.
ReadAllBytes
(
imagePath
);
byte
[]
src
=
System
.
IO
.
File
.
ReadAllBytes
(
imagePath
);
int
width
=
3072
;
int
width
=
3072
;
int
height
=
3072
;
int
height
=
3072
;
...
@@ -51,41 +48,19 @@ namespace Acc.Img
...
@@ -51,41 +48,19 @@ namespace Acc.Img
System
.
Runtime
.
InteropServices
.
Marshal
.
Copy
(
buff
,
0
,
bmpData
.
Scan0
,
bmpData
.
Stride
*
height
);
System
.
Runtime
.
InteropServices
.
Marshal
.
Copy
(
buff
,
0
,
bmpData
.
Scan0
,
bmpData
.
Stride
*
height
);
bmp
.
UnlockBits
(
bmpData
);
bmp
.
UnlockBits
(
bmpData
);
//bmp.Save(@"C:\Users\ASA\Desktop\222.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
//bmp.Save(@"C:\Users\ASA\Desktop\222.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
image
=
bmp
;
image
=
bmp
;
}
}
else
else
{
{
pngB
=
true
;
image
=
Image
.
FromFile
(
imagePath
);
image
=
Image
.
FromFile
(
imagePath
);
}
}
}
catch
(
Exception
)
{
}
}
catch
(
Exception
)
return
image
;
}
public
static
Image
FindCircle
(
Image
image
,
int
thresh
,
bool
inv
)
{
{
Mat
imageMat
=
BitmapConverter
.
ToMat
(
new
Bitmap
(
image
));
Cv2
.
PyrDown
(
imageMat
,
imageMat
);
Mat
threshMat
=
Threshhold
(
imageMat
,
thresh
,
inv
);
//Cv2.GaussianBlur(imageMat, imageMat, new OpenCvSharp.Size(7, 7), 5);
//threshMat = Threshhold(imageMat, thresh, inv);
Mat
k1
=
Mat
.
Ones
(
new
OpenCvSharp
.
Size
(
21
,
21
),
MatType
.
CV_8UC1
);
Cv2
.
MorphologyEx
(
threshMat
,
threshMat
,
MorphTypes
.
Open
,
k1
);
CircleSegment
[]
circles
=
Cv2
.
HoughCircles
(
threshMat
,
HoughMethods
.
Gradient
,
1
,
5
);
foreach
(
CircleSegment
circle
in
circles
)
{
Point2f
center
=
circle
.
Center
;
Cv2
.
Circle
(
imageMat
,
new
OpenCvSharp
.
Point
(
center
.
X
,
center
.
Y
),
(
int
)
circle
.
Radius
,
Scalar
.
White
);
}
}
return
BitmapConverter
.
ToBitmap
(
threshMat
)
;
return
image
;
}
}
...
@@ -96,10 +71,10 @@ namespace Acc.Img
...
@@ -96,10 +71,10 @@ namespace Acc.Img
/// <param name="thresh">阈值</param>
/// <param name="thresh">阈值</param>
/// <param name="inv">true表示元器件为白色,false表示元器件为黑色</param>
/// <param name="inv">true表示元器件为白色,false表示元器件为黑色</param>
/// <returns>二值化后的图像</returns>
/// <returns>二值化后的图像</returns>
public
static
Image
Threshhold
(
Image
image
,
int
thresh
,
bool
inv
=
true
)
public
static
Image
Threshhold
(
Image
image
,
int
thresh
)
{
{
Mat
imageMat
=
BitmapConverter
.
ToMat
(
new
Bitmap
(
image
));
Mat
imageMat
=
BitmapConverter
.
ToMat
(
new
Bitmap
(
image
));
Mat
threshMat
=
Threshhold
(
imageMat
,
thresh
,
inv
);
Mat
threshMat
=
Threshhold
(
imageMat
,
thresh
);
return
BitmapConverter
.
ToBitmap
(
threshMat
);
return
BitmapConverter
.
ToBitmap
(
threshMat
);
}
}
...
@@ -112,10 +87,10 @@ namespace Acc.Img
...
@@ -112,10 +87,10 @@ namespace Acc.Img
/// <param name="thresh">二值化阈值</param>
/// <param name="thresh">二值化阈值</param>
/// <param name="inv">true表示元器件为白色,false表示元器件为黑色</param>
/// <param name="inv">true表示元器件为白色,false表示元器件为黑色</param>
/// <returns>鼠标指向的元器件特征值</returns>
/// <returns>鼠标指向的元器件特征值</returns>
public
static
int
GetItemFeature
(
Image
image
,
int
markX
=
-
1
,
int
markY
=
-
1
,
int
thresh
=
-
1
,
bool
inv
=
true
)
public
static
int
GetItemFeature
(
Image
image
,
int
markX
=
-
1
,
int
markY
=
-
1
,
int
thresh
=
-
1
)
{
{
Mat
imageMat
=
BitmapConverter
.
ToMat
(
new
Bitmap
(
image
));
Mat
imageMat
=
BitmapConverter
.
ToMat
(
new
Bitmap
(
image
));
List
<
CvBlob
>
blobList
=
GetBlobs
(
imageMat
,
thresh
,
inv
);
List
<
CvBlob
>
blobList
=
GetBlobs
(
imageMat
,
thresh
);
int
blobCount
=
blobList
.
Count
;
int
blobCount
=
blobList
.
Count
;
int
selectIndex
=
blobCount
/
2
;
int
selectIndex
=
blobCount
/
2
;
if
(
markX
!=
-
1
&&
markY
!=
-
1
)
if
(
markX
!=
-
1
&&
markY
!=
-
1
)
...
@@ -136,7 +111,7 @@ namespace Acc.Img
...
@@ -136,7 +111,7 @@ namespace Acc.Img
if
(
markIndex
!=
-
1
)
if
(
markIndex
!=
-
1
)
{
{
int
area
=
blobList
[
markIndex
].
Area
;
int
area
=
blobList
[
markIndex
].
Area
;
area
=
area
*
5
/
3
-
23
;
area
=
area
*
5
/
3
-
23
;
return
area
;
return
area
;
}
}
}
}
...
@@ -145,12 +120,12 @@ namespace Acc.Img
...
@@ -145,12 +120,12 @@ namespace Acc.Img
public
static
int
GetItemFeatureAuto
(
Image
image
,
int
markX
=
-
1
,
int
markY
=
-
1
,
int
thresh
=
-
1
,
bool
inv
=
true
)
public
static
int
GetItemFeatureAuto
(
Image
image
,
int
markX
=
-
1
,
int
markY
=
-
1
,
int
thresh
=
-
1
,
bool
inv
=
true
)
{
{
Mat
imageMat
=
BitmapConverter
.
ToMat
(
new
Bitmap
(
image
));
Mat
imageMat
=
BitmapConverter
.
ToMat
(
new
Bitmap
(
image
));
List
<
CvBlob
>
blobList
=
GetBlobs
(
imageMat
,
thresh
,
inv
);
List
<
CvBlob
>
blobList
=
GetBlobs
(
imageMat
,
thresh
);
List
<
int
>
sampleList
=
new
List
<
int
>();
List
<
int
>
sampleList
=
new
List
<
int
>();
CvBlob
srcBlob
=
new
CvBlob
();
CvBlob
srcBlob
=
new
CvBlob
();
srcBlob
.
Area
=
-
1
;
srcBlob
.
Area
=
-
1
;
int
blobCount
=
blobList
.
Count
;
int
blobCount
=
blobList
.
Count
;
int
selectIndex
=
blobCount
/
2
+
blobCount
/
16
;
int
selectIndex
=
blobCount
/
2
+
blobCount
/
16
;
for
(
int
i
=
0
;
i
<
blobList
.
Count
;
i
++)
for
(
int
i
=
0
;
i
<
blobList
.
Count
;
i
++)
{
{
if
(
srcBlob
.
Area
==
-
1
)
if
(
srcBlob
.
Area
==
-
1
)
...
@@ -179,7 +154,7 @@ namespace Acc.Img
...
@@ -179,7 +154,7 @@ namespace Acc.Img
sampleList
.
Add
(
blobList
[
i
].
Area
);
sampleList
.
Add
(
blobList
[
i
].
Area
);
}
}
}
}
if
(
sampleList
.
Count
==
blobList
.
Count
-
1
||
i
==
blobList
.
Count
-
1
)
if
(
sampleList
.
Count
==
blobList
.
Count
-
1
||
i
==
blobList
.
Count
-
1
)
{
{
int
nums
=
0
;
int
nums
=
0
;
for
(
int
j
=
0
;
j
<
sampleList
.
Count
;
j
++)
for
(
int
j
=
0
;
j
<
sampleList
.
Count
;
j
++)
...
@@ -228,30 +203,21 @@ namespace Acc.Img
...
@@ -228,30 +203,21 @@ namespace Acc.Img
/// <param name="thresh"></param>
/// <param name="thresh"></param>
/// <param name="inv"></param>
/// <param name="inv"></param>
/// <returns></returns>
/// <returns></returns>
public
static
int
CountItems
(
ref
Image
image
,
int
item
Feature
,
int
thresh
=
-
1
,
bool
inv
=
true
)
public
static
int
CountItems
(
ref
Image
image
,
int
item
Area
)
{
{
Mat
imageMat
=
BitmapConverter
.
ToMat
(
new
Bitmap
(
image
));
Mat
imageMat
=
BitmapConverter
.
ToMat
(
new
Bitmap
(
image
));
Cv2
.
CvtColor
(
imageMat
,
imageMat
,
ColorConversionCodes
.
RGBA2BGR
);
Mat
grayMat
=
BitmapConverter
.
ToMat
(
new
Bitmap
(
image
));
Mat
grayMat
=
BitmapConverter
.
ToMat
(
new
Bitmap
(
image
));
Cv2
.
CvtColor
(
grayMat
,
grayMat
,
ColorConversionCodes
.
RGBA2RGB
);
Cv2
.
CvtColor
(
grayMat
,
grayMat
,
ColorConversionCodes
.
RGB2GRAY
);
if
(
pngB
)
CvBlobs
blobs
=
AutoThreshBlobs
(
ref
grayMat
,
itemArea
);
{
int
totalCount
=
findCircles
(
ref
imageMat
,
grayMat
,
blobs
,
itemArea
);
Cv2
.
Threshold
(
imageMat
,
imageMat
,
70
,
255
,
ThresholdTypes
.
Binary
);
}
//int totalCount = CountBlobs(blobs, itemArea, ref imageMat);
else
{
Cv2
.
Threshold
(
imageMat
,
imageMat
,
0
,
255
,
ThresholdTypes
.
Binary
);
}
List
<
CvBlob
>
blobList
=
GetBlobs
(
imageMat
,
thresh
,
inv
);
int
itemArea
=
(
itemFeature
+
23
)
*
3
/
5
;
if
(
itemArea
<=
0
)
{
itemArea
=
3
;
}
int
totalCount
=
CountBlobs
(
blobList
,
itemArea
,
ref
imageMat
);
image
=
BitmapConverter
.
ToBitmap
(
imageMat
);
image
=
BitmapConverter
.
ToBitmap
(
imageMat
);
return
totalCount
;
return
totalCount
;
}
}
private
static
void
FindCours
(
Mat
srcMat
,
Mat
threshMat
)
private
static
void
FindCours
(
Mat
srcMat
,
Mat
threshMat
)
{
{
Mat
[]
contours
=
null
;
Mat
[]
contours
=
null
;
...
@@ -334,7 +300,7 @@ namespace Acc.Img
...
@@ -334,7 +300,7 @@ namespace Acc.Img
{
{
maxX
=
anotherBlob
.
MaxX
;
maxX
=
anotherBlob
.
MaxX
;
}
}
if
(
anotherBlob
.
MaxY
>
maxY
)
if
(
anotherBlob
.
MaxY
>
maxY
)
{
{
maxY
=
anotherBlob
.
MaxY
;
maxY
=
anotherBlob
.
MaxY
;
}
}
...
@@ -378,20 +344,21 @@ namespace Acc.Img
...
@@ -378,20 +344,21 @@ namespace Acc.Img
int
leastNeighbourBlobCount
=
15
;
int
leastNeighbourBlobCount
=
15
;
int
selectIndex
=
blobList
.
Count
/
2
;
int
selectIndex
=
blobList
.
Count
/
2
;
markBlob
=
blobList
[
selectIndex
];
markBlob
=
blobList
[
selectIndex
];
for
(
int
i
=
selectIndex
;
i
<
blobList
.
Count
;
i
++)
for
(
int
i
=
selectIndex
;
i
<
blobList
.
Count
;
i
++)
{
{
CvBlob
blob
=
blobList
[
i
];
CvBlob
blob
=
blobList
[
i
];
int
blobArea
=
markBlob
.
Area
;
int
blobArea
=
markBlob
.
Area
;
if
(
BlobHasItem
(
avgArea
,
blob
)
==
1
)
if
(
BlobHasItem
(
avgArea
,
blob
)
==
1
)
// if(blobArea > 0.9 * avgArea && blobArea < 1.1 * avgArea)
// if(blobArea > 0.9 * avgArea && blobArea < 1.1 * avgArea)
{
{
//面积与给定的面积差不多,以其为中心,周围至少要有15个Blob
//面积与给定的面积差不多,以其为中心,周围至少要有15个Blob
int
neighbourCount
=
0
;
int
neighbourCount
=
0
;
int
blobRectSize
=
(
blob
.
MaxX
-
blob
.
MinX
)
<
(
blob
.
MaxY
-
blob
.
MinY
)
?
(
blob
.
MaxX
-
blob
.
MinX
)
:
(
blob
.
MaxY
-
blob
.
MinY
);
int
blobRectSize
=
(
blob
.
MaxX
-
blob
.
MinX
)
<
(
blob
.
MaxY
-
blob
.
MinY
)
?
(
blob
.
MaxX
-
blob
.
MinX
)
:
(
blob
.
MaxY
-
blob
.
MinY
);
double
radius
=
blobRectSize
;
double
radius
=
blobRectSize
;
while
(
neighbourCount
!=
blobList
.
Count
)
while
(
neighbourCount
!=
blobList
.
Count
)
{
{
neighbourCount
=
blobList
.
Count
(
b
=>
{
neighbourCount
=
blobList
.
Count
(
b
=>
{
if
(
BlobHasItem
(
avgArea
,
b
)
>=
1
)
if
(
BlobHasItem
(
avgArea
,
b
)
>=
1
)
{
{
double
distance
=
blob
.
Centroid
.
DistanceTo
(
b
.
Centroid
);
double
distance
=
blob
.
Centroid
.
DistanceTo
(
b
.
Centroid
);
...
@@ -414,100 +381,100 @@ namespace Acc.Img
...
@@ -414,100 +381,100 @@ namespace Acc.Img
}
}
return
Math
.
Sqrt
(
avgArea
);
return
Math
.
Sqrt
(
avgArea
);
}
}
/// <summary>
/// 获取Blob个数
/// </summary>
/// <param name="blobList"></param>
/// <param name="avgArea"></param>
/// <param name="srcMat"></param>
/// <returns></returns>
private
static
int
CountBlobs
(
List
<
CvBlob
>
blobList
,
int
avgArea
,
ref
Mat
srcMat
)
{
//List<CvBlob> filterBlobList = blobList.Where(b => b.Area > 0.3 * avgArea).ToList();
List
<
CvBlob
>
filterBlobList
=
blobList
.
Where
(
b
=>
b
.
Area
>
0
).
ToList
();
if
(
blobList
.
Count
==
0
)
{
return
0
;
}
//CvBlob markBlob = null;
//double labelStep = GetLabelStep(blobList, avgArea, out markBlob);
//string[] labels = new string[filterBlobList.Count];
//double markBlobX = markBlob.Centroid.X;
private
static
CvBlobs
AutoThreshBlobs
(
ref
Mat
imageMat
,
int
blobArea
)
//double markBlobY = markBlob.Centroid.Y;
{
//LabelBlobsInCircle(ref labels, filterBlobList, markBlobX, markBlobY, labelStep);
Mat
[]
mats
=
new
Mat
[]
{
imageMat
};
//一张图片,初始化为panda
Mat
hist
=
new
Mat
();
//用来接收直方图
int
[]
channels
=
new
int
[]
{
0
};
//一个通道,初始化为通道0
int
[]
histsize
=
new
int
[]
{
256
};
//一个通道,初始化为256箱子
Rangef
[]
range
=
new
Rangef
[
1
];
//一个通道,值范围
range
[
0
].
Start
=
0.0F
;
//从0开始(含)
range
[
0
].
End
=
256.0F
;
//到256结束(不含)
Mat
mask
=
new
Mat
();
//不做掩码
Cv2
.
CalcHist
(
mats
,
channels
,
mask
,
hist
,
1
,
histsize
,
range
);
//计算灰度图,dim为1 1维
double
total
=
0
;
for
(
int
i
=
0
;
i
<
256
;
i
++)
//灰度值总数量
{
total
=
total
+
hist
.
Get
<
double
>(
i
);
}
//int totalCount = 0;
double
percent
=
0
;
//for (int i = 0; i < labels.Length; i++)
int
startIndex
=
-
1
;
//{
int
endIndex
=
-
1
;
// if (labels[i] != null)
for
(
int
i
=
0
;
i
<
256
;
i
++)
//直方图
// {
{
// CvBlob blob = filterBlobList[i];
double
len
=
hist
.
Get
<
double
>(
i
);
// Scalar color = Scalar.Red;
if
(
len
>
100
)
// int count = BlobHasItem(avgArea, blob);
{
//灰度值的像素数小于100的忽略
// if (count > 0)
percent
=
percent
+
len
/
total
;
// {
if
(
startIndex
==
-
1
)
// if (count == 1)
{
// {
startIndex
=
i
;
// color = Scalar.Green;
}
// }
//近似的认为元器件的灰度值 数量占总数的百分比小于10%
// else if (count == 2)
if
(
percent
>
0.1
)
// {
{
// color = Scalar.Blue;
endIndex
=
i
-
1
;
// //Cv2.PutText(srcMat, count + "", blob.Centroid, HersheyFonts.HersheySimplex, 0.5, color);
break
;
// }
}
// else if (count >= 3)
}
// {
}
// color = Scalar.Red;
// Point2d center = blob.Centroid;
// Cv2.PutText(srcMat, count + "", new OpenCvSharp.Point(center.X, center.Y), HersheyFonts.HersheySimplex, 0.5, color);
// }
// totalCount = totalCount + count;
int
avgIndex
=
(
startIndex
+
endIndex
)
/
2
;
// blob.Contour.Render(srcMat, color);
Mat
threshMat
=
new
Mat
();
// }
Cv2
.
Threshold
(
imageMat
,
threshMat
,
avgIndex
,
255
,
ThresholdTypes
.
BinaryInv
);
// }
CvBlobs
resultBlobs
=
new
CvBlobs
();
//}
resultBlobs
.
Label
(
threshMat
);
List
<
CvBlob
>
autoBlobList
=
resultBlobs
.
Values
.
Where
(
b
=>
b
.
Area
>
blobArea
).
ToList
();
int
blobCount
=
resultBlobs
.
Count
();
int
threshIndex
=
avgIndex
;
double
theArea
=
blobArea
*
0.8
;
if
(
theArea
<
1
)
theArea
=
1
;
int
totalCount
=
0
;
while
(
true
)
foreach
(
CvBlob
blob
in
filterBlobList
)
{
Scalar
color
=
Scalar
.
Red
;
if
(
blob
.
MaxX
-
blob
.
MinX
>
450
&&
blob
.
MaxY
-
blob
.
MinY
>
450
)
continue
;
int
count
=
BlobHasItem
(
avgArea
,
blob
);
if
(
count
>
0
)
{
{
if
(
count
==
1
)
//阈值向下走,找满足条件Blob数量最多的
threshIndex
=
threshIndex
-
1
;
Cv2
.
Threshold
(
imageMat
,
threshMat
,
threshIndex
,
255
,
ThresholdTypes
.
BinaryInv
);
CvBlobs
blobs
=
new
CvBlobs
();
blobs
.
Label
(
threshMat
);
List
<
CvBlob
>
blobList
=
blobs
.
Values
.
Where
(
b
=>
b
.
Area
>
theArea
).
ToList
();
if
(
blobList
.
Count
>
blobCount
)
{
{
color
=
Scalar
.
Green
;
resultBlobs
=
blobs
;
blobCount
=
blobList
.
Count
;
}
}
else
if
(
count
==
2
)
else
{
{
color
=
Scalar
.
Blue
;
break
;
//Cv2.PutText(srcMat, count + "", blob.Centroid, HersheyFonts.HersheySimplex, 0.5, color);
}
}
}
else
if
(
count
>=
3
)
threshIndex
=
avgIndex
;
while
(
true
)
{
{
color
=
Scalar
.
Red
;
//阈值向上走,找满足条件Blob数量最多的
Point2d
center
=
blob
.
Centroid
;
threshIndex
=
threshIndex
+
1
;
Cv2
.
PutText
(
srcMat
,
count
+
""
,
new
OpenCvSharp
.
Point
(
center
.
X
,
center
.
Y
),
HersheyFonts
.
HersheySimplex
,
0.5
,
color
);
Cv2
.
Threshold
(
imageMat
,
threshMat
,
threshIndex
,
255
,
ThresholdTypes
.
BinaryInv
);
CvBlobs
blobs
=
new
CvBlobs
();
blobs
.
Label
(
threshMat
);
List
<
CvBlob
>
blobList
=
blobs
.
Values
.
Where
(
b
=>
b
.
Area
>
theArea
).
ToList
();
if
(
blobList
.
Count
>
blobCount
)
{
resultBlobs
=
blobs
;
blobCount
=
blobList
.
Count
;
}
}
totalCount
=
totalCount
+
count
;
else
blob
.
Contour
.
Render
(
srcMat
,
color
);
{
break
;
}
}
}
}
string
countText
=
"Count: "
+
totalCount
;
imageMat
=
threshMat
;
int
baseLine
=
0
;
Console
.
WriteLine
(
threshIndex
+
"==== Blob: "
+
blobCount
+
" Area:"
+
theArea
);
OpenCvSharp
.
Size
textSize
=
Cv2
.
GetTextSize
(
countText
,
HersheyFonts
.
HersheySimplex
,
1
,
1
,
out
baseLine
);
return
resultBlobs
;
Cv2
.
PutText
(
srcMat
,
countText
,
new
OpenCvSharp
.
Point
(
srcMat
.
Width
/
2
-
textSize
.
Width
/
2
,
srcMat
.
Height
/
2
-
textSize
.
Height
/
2
),
HersheyFonts
.
HersheySimplex
,
1
,
Scalar
.
Blue
);
//Cv2.Circle(srcMat, markBlob.Centroid, (int)labelStep, Scalar.Red, 2);
return
totalCount
;
}
}
/// <summary>
/// <summary>
/// 二值化图像
/// 二值化图像
/// </summary>
/// </summary>
...
@@ -515,83 +482,24 @@ namespace Acc.Img
...
@@ -515,83 +482,24 @@ namespace Acc.Img
/// <param name="thresh"></param>
/// <param name="thresh"></param>
/// <param name="inv"></param>
/// <param name="inv"></param>
/// <returns></returns>
/// <returns></returns>
private
static
Mat
Threshhold
(
Mat
imageMat
,
int
thresh
=
-
1
,
bool
inv
=
false
)
private
static
Mat
Threshhold
(
Mat
imageMat
,
int
thresh
=
-
1
)
{
{
Mat
dst
=
new
Mat
();
Mat
dst
=
new
Mat
();
Cv2
.
CvtColor
(
imageMat
,
dst
,
ColorConversionCodes
.
RGB2GRAY
);
Cv2
.
CvtColor
(
imageMat
,
dst
,
ColorConversionCodes
.
RGB2GRAY
);
//if (selectB)
//{
// //全局二值化
// Cv2.Threshold(dst, dst, 30, 255, ThresholdTypes.Binary);
//}
//else
//{
// //全局二值化
// Cv2.Threshold(dst, dst, 0, 255, ThresholdTypes.Binary);
//}
//if (selectB)
//{
// if (thresh == -1)
// {
// //自动局部二值化
// Binarizer.Sauvola(dst, dst, 21, 0.2, 32);
// }
// else
// {
// //全局二值化
// if (pngB)
// {
// Cv2.Threshold(dst, dst, 70, 255, ThresholdTypes.Binary);
// }
// else
// {
// Cv2.Threshold(dst, dst, 0, 255, ThresholdTypes.Binary);
// }
// }
// if (inv)
// {
// if (pngB)
// {
// Cv2.Threshold(dst, dst, 70, 150, ThresholdTypes.BinaryInv);
// }
// else
// {
// Cv2.Threshold(dst, dst, 0, 150, ThresholdTypes.BinaryInv);
// }
// }
//}
//else
//{
// if (pngB)
// {
// Cv2.Threshold(dst, dst, 70, 255, ThresholdTypes.Binary);
// Cv2.Threshold(dst, dst, 0, 150, ThresholdTypes.BinaryInv);
// }
// else
// {
// Cv2.Threshold(dst, dst, 0, 255, ThresholdTypes.Binary);
// Cv2.Threshold(dst, dst, 0, 150, ThresholdTypes.BinaryInv);
// }
//}
if
(
thresh
==
-
1
)
if
(
thresh
==
-
1
)
{
{
//全局自动二值 化
Cv2
.
Threshold
(
dst
,
dst
,
0
,
255
,
ThresholdTypes
.
Otsu
|
ThresholdTypes
.
BinaryInv
);
//自动局部二值化
//自动局部二值化
Binarizer
.
Sauvola
(
dst
,
dst
,
21
,
0.2
,
32
);
//Binarizer.Sauvola(dst, dst, 221, 0.02, 232);
//Cv2.AdaptiveThreshold(dst, dst, 255, AdaptiveThresholdTypes.GaussianC, ThresholdTypes.Binary, 5, 0);
}
}
else
else
{
{
//全局二值化
//二值化
Cv2
.
Threshold
(
dst
,
dst
,
0
,
255
,
ThresholdTypes
.
Otsu
);
Cv2
.
Threshold
(
dst
,
dst
,
thresh
,
255
,
ThresholdTypes
.
BinaryInv
);
}
if
(
inv
)
{
Cv2
.
Threshold
(
dst
,
dst
,
0
,
thresh
,
ThresholdTypes
.
BinaryInv
|
ThresholdTypes
.
Otsu
);
}
}
return
dst
;
return
dst
;
}
}
/// <summary>
/// <summary>
...
@@ -601,13 +509,10 @@ namespace Acc.Img
...
@@ -601,13 +509,10 @@ namespace Acc.Img
/// <param name="thresh"></param>
/// <param name="thresh"></param>
/// <param name="inv"></param>
/// <param name="inv"></param>
/// <returns></returns>
/// <returns></returns>
private
static
List
<
CvBlob
>
GetBlobs
(
Mat
imageMat
,
int
thresh
=
-
1
,
bool
inv
=
false
)
private
static
List
<
CvBlob
>
GetBlobs
(
Mat
imageMat
,
int
thresh
=
-
1
)
{
{
Cv2
.
CvtColor
(
imageMat
,
imageMat
,
ColorConversionCodes
.
RGBA2BGR
);
Cv2
.
CvtColor
(
imageMat
,
imageMat
,
ColorConversionCodes
.
RGBA2BGR
);
//Cv2.CvtColor(imageMat, imageMat, ColorConversionCodes.RGB2GRAY);
Mat
dst
=
Threshhold
(
imageMat
,
thresh
);
Mat
dst
=
Threshhold
(
imageMat
,
thresh
,
inv
);
Mat
k1
=
Mat
.
Ones
(
new
OpenCvSharp
.
Size
(
1
,
1
),
MatType
.
CV_8UC1
);
Cv2
.
MorphologyEx
(
dst
,
dst
,
MorphTypes
.
Open
,
k1
);
CvBlobs
blobs
=
new
CvBlobs
();
CvBlobs
blobs
=
new
CvBlobs
();
blobs
.
Label
(
dst
);
blobs
.
Label
(
dst
);
List
<
CvBlob
>
blobList
=
blobs
.
Values
.
Where
(
b
=>
b
.
Area
>
0
).
ToList
();
List
<
CvBlob
>
blobList
=
blobs
.
Values
.
Where
(
b
=>
b
.
Area
>
0
).
ToList
();
...
@@ -631,7 +536,7 @@ namespace Acc.Img
...
@@ -631,7 +536,7 @@ namespace Acc.Img
}
}
if
(
blobArea
<
minArea
)
if
(
blobArea
<
minArea
)
{
{
return
1
;
return
0
;
}
}
//if (blobArea >= 0.5 * averageArea && blobArea <= 1.5 * averageArea)
//if (blobArea >= 0.5 * averageArea && blobArea <= 1.5 * averageArea)
//{
//{
...
@@ -645,8 +550,8 @@ namespace Acc.Img
...
@@ -645,8 +550,8 @@ namespace Acc.Img
//{
//{
// return 3;
// return 3;
//}
//}
int
count
=
(
int
)((
blobArea
+
1.5
*
averageArea
)
/
(
1.5
*
averageArea
));
int
count
=
(
int
)((
blobArea
+
1.5
*
averageArea
)
/
(
1.5
*
averageArea
));
if
(
count
==
0
)
if
(
count
==
0
)
{
{
count
=
1
;
count
=
1
;
}
}
...
@@ -713,11 +618,11 @@ namespace Acc.Img
...
@@ -713,11 +618,11 @@ namespace Acc.Img
//翻转图层
//翻转图层
if
(
needRevertLayer
)
if
(
needRevertLayer
)
{
{
return
new
Bitmap
[]
{
filter_bitmap
,
src_bitmap
};
return
new
Bitmap
[]
{
filter_bitmap
,
src_bitmap
};
}
}
else
else
{
{
return
new
Bitmap
[]
{
src_bitmap
,
filter_bitmap
};
return
new
Bitmap
[]
{
src_bitmap
,
filter_bitmap
};
}
}
}
}
/// <summary>
/// <summary>
...
@@ -751,11 +656,9 @@ namespace Acc.Img
...
@@ -751,11 +656,9 @@ namespace Acc.Img
return
bmp
;
return
bmp
;
}
}
private
static
List
<
OpenCvSharp
.
Point
>
findContourPoints
(
CvBlob
blob
)
private
static
List
<
OpenCvSharp
.
Point
>
toContourPoints
(
CvContourChainCode
contour
)
{
{
CvContourChainCode
contour
=
blob
.
Contour
;
List
<
OpenCvSharp
.
Point
>
contourPoints
=
new
List
<
OpenCvSharp
.
Point
>();
List
<
OpenCvSharp
.
Point
>
contourPoints
=
new
List
<
OpenCvSharp
.
Point
>();
contourPoints
.
Add
(
contour
.
StartingPoint
);
contourPoints
.
Add
(
contour
.
StartingPoint
);
int
x
=
contour
.
StartingPoint
.
X
;
int
x
=
contour
.
StartingPoint
.
X
;
int
y
=
contour
.
StartingPoint
.
Y
;
int
y
=
contour
.
StartingPoint
.
Y
;
...
@@ -795,144 +698,354 @@ namespace Acc.Img
...
@@ -795,144 +698,354 @@ namespace Acc.Img
}
}
return
null
;
return
null
;
}
}
public
static
Image
Mark
(
Image
image
,
int
markX
=
-
1
,
int
markY
=
-
1
,
int
thresh
=
-
1
,
bool
inv
=
true
)
/// <summary>
/// 查找Blob中包含的所有与给定半径差不多的内接圆
/// </summary>
/// <param name="matDistanceArr"></param>
/// <param name="blobs"></param>
/// <param name="blob"></param>
/// <param name="reelCenter"></param>
/// <param name="oneBlobWidth"></param>
/// <param name="oneBlobRadius"></param>
/// <returns></returns>
public
static
SplitItem
findCircleInBlob
(
ref
double
[,]
matDistanceArr
,
CvBlobs
blobs
,
CvBlob
blob
,
Point2d
reelCenter
,
double
oneBlobWidth
=
-
1
,
double
oneBlobRadius
=
-
1
)
{
{
Mat
imageMat
=
BitmapConverter
.
ToMat
(
new
Bitmap
(
image
));
SplitItem
item
=
new
SplitItem
();
List
<
CvBlob
>
blobList
=
GetBlobs
(
imageMat
,
thresh
,
inv
);
while
(
true
)
//TODO:查找标记Blob,这里可遍历blobList,对BlobHasItem结果为1的blob进行标记,查找最小的内接半径
CvBlob
markBlob
=
findMarkBlob
(
blobList
,
markX
,
markY
,
thresh
,
inv
);
if
(
markBlob
!=
null
)
{
OpenCvSharp
.
Point
center
=
new
OpenCvSharp
.
Point
()
;
double
r
=
0
;
findCircle
(
markBlob
,
out
center
,
out
r
);
Cv2
.
Circle
(
imageMat
,
center
,
(
int
)
r
,
Scalar
.
Red
);
Console
.
WriteLine
(
""
+
r
);
int
markArea
=
markBlob
.
Area
;
int
totalCount
=
0
;
foreach
(
CvBlob
blob
in
blobList
)
{
{
int
count
=
BlobHasItem
(
markArea
,
blob
);
bool
hasFind
=
false
;
totalCount
=
totalCount
+
count
;
for
(
int
y
=
blob
.
MinY
;
y
<
blob
.
MaxY
;
y
++)
if
(
count
==
1
)
{
{
//单个Blob
for
(
int
x
=
blob
.
MinX
;
x
<
blob
.
MaxX
;
x
++)
blob
.
Contour
.
Render
(
imageMat
,
Scalar
.
Green
);
{
double
distance
=
matDistanceArr
[
x
,
y
];
if
(
distance
>
0
)
{
int
label
=
blobs
.
GetLabel
(
x
,
y
);
if
(
label
!=
blob
.
Label
)
{
//不是当前Blob的像素
matDistanceArr
[
x
,
y
]
=
0
;
continue
;
}
}
else
if
(
count
>
0
&&
count
<
100
)
if
(!
item
.
isEnd
)
{
{
//查找对大一点的Blob的内接圆数量,进行标记
double
distanceToCircle
=
item
.
minDistanceToCircles
(
x
,
y
,
reelCenter
);
Stopwatch
sw
=
new
Stopwatch
();
if
(
distanceToCircle
==
0
)
sw
.
Start
();
List
<
OpenCvSharp
.
Point
>
centers
=
markBlobInImage
(
blob
,
r
);
foreach
(
OpenCvSharp
.
Point
c
in
centers
)
{
{
Cv2
.
Circle
(
imageMat
,
c
,
(
int
)
r
,
Scalar
.
Red
);
matDistanceArr
[
x
,
y
]
=
0
;
continue
;
}
}
sw
.
Stop
();
if
(
distanceToCircle
>
0
&&
distanceToCircle
<
distance
)
Console
.
WriteLine
(
"耗时:"
+
sw
.
ElapsedMilliseconds
+
" ms 数量:"
+
centers
.
Count
);
{
distance
=
distanceToCircle
;
matDistanceArr
[
x
,
y
]
=
distance
;
}
if
(
distance
>
item
.
currentMaxRadius
)
{
item
.
currentMaxRadius
=
distance
;
item
.
centerX
=
x
;
item
.
centerY
=
y
;
if
(
oneBlobRadius
!=
-
1
&&
distance
>=
oneBlobRadius
)
{
item
.
calOneItem
(
oneBlobRadius
);
hasFind
=
true
;
break
;
}
}
}
}
}
}
}
return
BitmapConverter
.
ToBitmap
(
imageMat
);
}
if
(
hasFind
)
{
break
;
}
}
if
(!
hasFind
)
{
item
.
calOneItem
(
oneBlobRadius
);
}
if
(
item
.
isEnd
)
{
break
;
}
}
return
item
;
}
}
/// <summary>
/// <summary>
/// 查找Blob
包含多少个指定半径的圆
/// 查找Blob
s包含的元器件数量
/// </summary>
/// </summary>
/// <param name="blob"></param>
/// <param name="srcMat"></param>
/// <param name="radius">指定半径</param>
/// <param name="threshMat"></param>
/// <returns>找到的圆的中心点列表,一个中心点为一个圆</returns>
/// <param name="blobs"></param>
private
static
List
<
OpenCvSharp
.
Point
>
markBlobInImage
(
CvBlob
blob
,
double
radius
)
/// <param name="avgArea"></param>
{
/// <returns></returns>
List
<
OpenCvSharp
.
Point
>
centers
=
new
List
<
OpenCvSharp
.
Point
>();
public
static
int
findCircles
(
ref
Mat
srcMat
,
Mat
threshMat
,
CvBlobs
blobs
,
int
avgArea
)
List
<
OpenCvSharp
.
Point
>
contourPoints
=
findContourPoints
(
blob
);
{
CvContourPolygon
polygon
=
blob
.
Contour
.
ConvertToPolygon
();
Mat
distanceMat
=
new
Mat
();
//从左向右,从上到下遍历
Cv2
.
DistanceTransform
(
threshMat
,
distanceMat
,
DistanceTypes
.
L2
,
DistanceMaskSize
.
Mask3
);
int
x
=
blob
.
MinX
;
double
[,]
distanceArr
=
new
double
[
threshMat
.
Cols
,
threshMat
.
Rows
];
while
(
x
<=
blob
.
MaxX
)
Console
.
WriteLine
(
"Start to distance array"
);
{
for
(
int
y
=
0
;
y
<
threshMat
.
Rows
;
y
++)
int
y
=
blob
.
MinY
;
{
while
(
y
<=
blob
.
MaxY
)
for
(
int
x
=
0
;
x
<
threshMat
.
Cols
;
x
++)
{
{
//当前的遍历的点
distanceArr
[
x
,
y
]
=
distanceMat
.
At
<
float
>(
y
,
x
);
OpenCvSharp
.
Point
currentPoint
=
new
OpenCvSharp
.
Point
(
x
,
y
);
}
double
distance
=
Cv2
.
PointPolygonTest
(
contourPoints
,
currentPoint
,
true
);
}
//TODO: 内轮廓也需要判断
if
(
distance
>=
radius
)
Dictionary
<
int
,
SplitItem
>
blobCircles
=
new
Dictionary
<
int
,
SplitItem
>();
{
//当前点到轮廓的最小距离大于半径时,判断是否与其他圆相交,如果相交,忽略这个点
Console
.
WriteLine
(
"Start find reel center"
);
bool
valid
=
true
;
Point2d
reelCenter
=
new
Point2d
(
0
,
0
)
;
foreach
(
OpenCvSharp
.
Point
c
in
centers
)
//查找中心
{
foreach
(
CvBlob
blob
in
blobs
.
Values
)
double
dis
=
currentPoint
.
DistanceTo
(
c
);
{
if
(
dis
<
2
*
radius
)
int
count
=
BlobHasItem
(
avgArea
,
blob
);
{
if
(
count
>
10
&&
reelCenter
.
X
==
0
)
valid
=
false
;
{
Point2d
center
=
blob
.
Centroid
;
//中间的圆,查找圆心
if
(
center
.
DistanceTo
(
new
Point2d
(
srcMat
.
Cols
/
2
,
srcMat
.
Rows
/
2
))
<
200
)
{
reelCenter
=
center
;
srcMat
.
Line
(
new
OpenCvSharp
.
Point
(
center
.
X
-
10
,
center
.
Y
),
new
OpenCvSharp
.
Point
(
center
.
X
+
10
,
center
.
Y
),
Scalar
.
Blue
);
srcMat
.
Line
(
new
OpenCvSharp
.
Point
(
center
.
X
,
center
.
Y
-
10
),
new
OpenCvSharp
.
Point
(
center
.
X
,
center
.
Y
+
10
),
Scalar
.
Blue
);
break
;
break
;
}
}
}
}
if
(
valid
)
}
Console
.
WriteLine
(
"Start find reel Max Radius, max Width"
);
//最大
double
maxRadius
=
0
;
double
maxWidth
=
0
;
foreach
(
CvBlob
blob
in
blobs
.
Values
)
{
int
count
=
BlobHasItem
(
avgArea
,
blob
);
if
(
count
==
1
)
{
{
//找到一个,从当前点向下偏移一个半径的距离
if
(
blob
.
Rect
.
Width
>
maxWidth
)
y
=
(
int
)(
y
+
radius
);
{
Console
.
WriteLine
(
""
+
x
+
", "
+
y
+
" dis="
+
distance
+
" "
);
maxWidth
=
blob
.
Rect
.
Width
;
centers
.
Add
(
currentPoint
);
}
}
else
if
(
blob
.
Rect
.
Height
>
maxWidth
)
{
maxWidth
=
blob
.
Rect
.
Height
;
}
SplitItem
item
=
findCircleInBlob
(
ref
distanceArr
,
blobs
,
blob
,
reelCenter
);
foreach
(
Circle
c
in
item
.
circles
)
{
if
(
c
.
radius
>
maxRadius
||
maxRadius
==
0
)
{
{
//与其他圆相交,忽略,继续下一个点
maxRadius
=
c
.
radius
;
y
++;
}
}
//srcMat.Circle(c.x, c.y, (int)c.radius, Scalar.Green);
}
}
else
}
}
Console
.
WriteLine
(
"Start count"
);
int
totalCount
=
0
;
foreach
(
CvBlob
blob
in
blobs
.
Values
)
{
int
count
=
BlobHasItem
(
avgArea
,
blob
);
if
(
count
==
1
)
{
//单个元器件
totalCount
=
totalCount
+
1
;
srcMat
.
Circle
((
int
)
blob
.
Centroid
.
X
,
(
int
)
blob
.
Centroid
.
Y
,
(
int
)
maxRadius
/
2
,
Scalar
.
LightGreen
);
}
else
if
(
count
>
1
)
{
if
(
count
>
20
)
{
{
//当前点到轮廓的最小距离小于半径,继续下一个点
//中间的圆,去除
y
++;
if
(
blob
.
Centroid
.
DistanceTo
(
new
Point2d
(
srcMat
.
Cols
/
2
,
srcMat
.
Rows
/
2
))
<
200
)
{
continue
;
}
}
}
}
x
++;
//多个元器件,查找 所有圆
SplitItem
item
=
findCircleInBlob
(
ref
distanceArr
,
blobs
,
blob
,
reelCenter
,
maxWidth
,
maxRadius
);
//对所有圆进行分组
List
<
List
<
Circle
>>
groupCircles
=
item
.
groupCircles
(
maxWidth
,
maxRadius
,
reelCenter
);
Scalar
color
=
Scalar
.
RandomColor
();
blob
.
Contour
.
Render
(
srcMat
,
color
);
foreach
(
List
<
Circle
>
groupCircle
in
groupCircles
)
{
Circle
c
=
groupCircle
[
0
];
srcMat
.
Circle
(
c
.
x
,
c
.
y
,
(
int
)
c
.
radius
/
2
,
Scalar
.
Yellow
);
totalCount
=
totalCount
+
1
;
//Scalar color = Scalar.RandomColor();
//foreach (Circle c in groupCircle)
//{
// srcMat.Circle(c.x, c.y, (int)c.radius, color);
//}
}
}
}
return
centers
;
}
}
/// <summary>
Cv2
.
PutText
(
srcMat
,
totalCount
+
""
,
new
OpenCvSharp
.
Point
(
reelCenter
.
X
-
40
,
reelCenter
.
Y
+
30
),
HersheyFonts
.
HersheySimplex
,
1.0
,
Scalar
.
LightGreen
);
/// 查找Blob最大的内接圆
Console
.
WriteLine
(
"==========="
+
totalCount
);
/// </summary>
return
totalCount
;
/// <param name="blob"></param>
/// <param name="centerPoint"></param>
}
/// <param name="r"></param>
private
static
void
findCircle
(
CvBlob
blob
,
out
OpenCvSharp
.
Point
centerPoint
,
out
double
r
)
//TODO: 测试距离变换,用后删除
{
public
static
Image
DistanceTransform
(
Image
image
)
//TODO: 需要进行修改,找多个,这里只找了一个
{
List
<
OpenCvSharp
.
Point
>
contourPoints
=
findContourPoints
(
blob
);
Mat
imageMat
=
BitmapConverter
.
ToMat
(
new
Bitmap
(
image
));
OpenCvSharp
.
Point
center
=
new
OpenCvSharp
.
Point
(-
1
,-
1
);
Mat
gray
=
new
Mat
();
double
ridus
=
0
;
Cv2
.
CvtColor
(
imageMat
,
gray
,
ColorConversionCodes
.
RGB2GRAY
);
for
(
int
x
=
blob
.
MinX
;
x
<
blob
.
MaxX
;
x
++)
////开运算
Mat
k1
=
Mat
.
Ones
(
new
OpenCvSharp
.
Size
(
1
,
1
),
MatType
.
CV_8UC1
);
Cv2
.
MorphologyEx
(
gray
,
gray
,
MorphTypes
.
Open
,
k1
,
new
OpenCvSharp
.
Point
(
0
,
0
),
3
);
Mat
distanceMat
=
new
Mat
();
Mat
labels
=
new
Mat
()
;
Cv2
.
DistanceTransform
(
gray
,
distanceMat
,
DistanceTypes
.
L2
,
DistanceMaskSize
.
Mask3
)
;
Cv2
.
Normalize
(
distanceMat
,
gray
,
0
,
255
,
NormTypes
.
MinMax
);
gray
.
ConvertTo
(
gray
,
MatType
.
CV_8UC1
);
Cv2
.
Threshold
(
gray
,
gray
,
0
,
255
,
ThresholdTypes
.
Otsu
);
Mat
colorImg
=
Mat
.
Zeros
(
gray
.
Size
(),
MatType
.
CV_8UC3
);
Cv2
.
ConnectedComponents
(
gray
,
labels
,
PixelConnectivity
.
Connectivity8
);
Dictionary
<
int
,
SplitItem
>
blobCircles
=
new
Dictionary
<
int
,
SplitItem
>();
for
(
int
y
=
0
;
y
<
labels
.
Rows
;
y
++)
{
for
(
int
x
=
0
;
x
<
labels
.
Cols
;
x
++)
{
int
label
=
labels
.
At
<
int
>(
y
,
x
);
float
distance
=
distanceMat
.
At
<
float
>(
y
,
x
);
SplitItem
item
=
new
SplitItem
();
if
(
blobCircles
.
ContainsKey
(
label
))
{
item
=
blobCircles
[
label
];
}
if
(
distance
>
item
.
currentMaxRadius
)
{
item
.
currentMaxRadius
=
distance
;
item
.
centerX
=
x
;
item
.
centerY
=
y
;
}
blobCircles
[
label
]
=
item
;
byte
b
=
(
byte
)(
label
%
255
);
byte
g
=
0
;
if
(
b
<
128
&&
b
>
0
)
{
g
=
(
byte
)(
255
-
b
);
}
Vec3b
color
=
new
Vec3b
(
b
,
g
,
0
);
colorImg
.
Set
<
Vec3b
>(
y
,
x
,
color
);
}
}
foreach
(
SplitItem
circle
in
blobCircles
.
Values
)
{
circle
.
calOneItem
(-
1
);
}
while
(
true
)
{
for
(
int
y
=
0
;
y
<
labels
.
Rows
;
y
++)
{
for
(
int
x
=
0
;
x
<
labels
.
Cols
;
x
++)
{
int
label
=
labels
.
At
<
int
>(
y
,
x
);
if
(
label
==
0
)
continue
;
SplitItem
item
=
new
SplitItem
();
if
(
blobCircles
.
ContainsKey
(
label
))
{
{
for
(
int
y
=
blob
.
MinY
;
y
<
blob
.
MaxY
;
y
++)
item
=
blobCircles
[
label
];
}
if
(!
item
.
isEnd
)
{
double
distance
=
distanceMat
.
At
<
float
>(
y
,
x
);
//此Blob未结束
// bool validPoint = item.isValidPoint(x, y);
bool
validPoint
=
false
;
if
(
validPoint
)
{
if
(
distance
>
item
.
currentMaxRadius
)
{
item
.
currentMaxRadius
=
distance
;
item
.
centerX
=
x
;
item
.
centerY
=
y
;
blobCircles
[
label
]
=
item
;
}
}
}
}
}
bool
needContinue
=
false
;
foreach
(
SplitItem
circle
in
blobCircles
.
Values
)
{
{
OpenCvSharp
.
Point
currentPoint
=
new
OpenCvSharp
.
Point
(
x
,
y
);
circle
.
calOneItem
();
double
minDistance
=
-
1
;
if
(!
circle
.
isEnd
)
foreach
(
OpenCvSharp
.
Point
p
in
contourPoints
)
{
{
double
distance
=
currentPoint
.
DistanceTo
(
p
);
needContinue
=
true
;
if
(
distance
<
minDistance
||
minDistance
==
-
1
)
}
}
if
(!
needContinue
)
{
{
minDistance
=
distance
;
break
;
}
}
}
}
if
(
minDistance
>
ridus
)
int
totalCount
=
0
;
foreach
(
SplitItem
item
in
blobCircles
.
Values
)
{
foreach
(
Circle
circle
in
item
.
circles
)
{
{
ridus
=
minDistance
;
Cv2
.
Circle
(
colorImg
,
circle
.
x
,
circle
.
y
,
(
int
)
circle
.
radius
,
Scalar
.
White
);
center
=
currentPoint
;
totalCount
++;
}
}
Console
.
WriteLine
(
"Total: "
+
totalCount
);
return
BitmapConverter
.
ToBitmap
(
colorImg
);
//dist.SaveImage("d:\\image\\dsitdist1.jpg");
//Cv2.Threshold(dist, dist, 79, 255, ThresholdTypes.Binary);
//Cv2.CvtColor(dist,dist,ColorConversionCodes.BGRA2BGR);
//dist.ConvertTo(dist, MatType.CV_8UC1);
//image = BitmapConverter.ToBitmap(dist);
//return image;
}
}
/// <summary>
/// 获取单个元器件的特征
/// </summary>
/// <param name="image"></param>
/// <param name="markX"></param>
/// <param name="markY"></param>
/// <returns></returns>
public
static
int
GetFeature
(
ref
Image
image
,
int
markX
,
int
markY
)
{
Mat
imageMat
=
BitmapConverter
.
ToMat
(
new
Bitmap
(
image
));
Mat
dst
=
new
Mat
();
Cv2
.
CvtColor
(
imageMat
,
dst
,
ColorConversionCodes
.
RGB2GRAY
);
//全局二值化
Cv2
.
Threshold
(
dst
,
dst
,
0
,
255
,
ThresholdTypes
.
Otsu
|
ThresholdTypes
.
BinaryInv
);
image
=
BitmapConverter
.
ToBitmap
(
dst
);
CvBlobs
blobs
=
new
CvBlobs
();
blobs
.
Label
(
dst
);
foreach
(
CvBlob
blob
in
blobs
.
Values
)
{
if
(
blob
.
Rect
.
Contains
(
new
OpenCvSharp
.
Point
(
markX
,
markY
)))
{
return
blob
.
Area
;
}
}
}
}
centerPoint
=
center
;
return
-
1
;
r
=
ridus
;
}
}
}
}
}
}
AccImage/SplitItem.cs
0 → 100644
查看文件 @
8511f26
using
OpenCvSharp
;
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.Threading.Tasks
;
namespace
AccImage
{
public
class
SplitItem
{
public
bool
isEnd
=
false
;
public
double
avgRadius
=
0
;
public
int
centerX
=
0
;
public
int
centerY
=
0
;
public
double
currentMaxRadius
=
0
;
public
List
<
Circle
>
circles
=
new
List
<
Circle
>();
/// <summary>
/// 一遍结束后调用
/// </summary>
public
void
calOneItem
(
double
theFixRadius
=-
1
)
{
//该半径是否有效
bool
isValid
=
false
;
if
(
avgRadius
==
0
)
{
isValid
=
true
;
}
else
{
//与平均半径差值在10%以内,认为OK
double
diff
=
avgRadius
-
currentMaxRadius
;
if
(
diff
/
avgRadius
<=
0.2
)
{
isValid
=
true
;
}
}
if
(
isValid
)
{
Circle
circle
=
new
Circle
();
if
(
theFixRadius
!=
-
1
&&
currentMaxRadius
>
theFixRadius
)
{
currentMaxRadius
=
theFixRadius
;
}
circle
.
radius
=
currentMaxRadius
;
circle
.
x
=
centerX
;
circle
.
y
=
centerY
;
circles
.
Add
(
circle
);
currentMaxRadius
=
0
;
centerX
=
0
;
centerY
=
0
;
//平均半径
double
total
=
0
;
foreach
(
Circle
c
in
circles
)
{
total
=
total
+
c
.
radius
;
}
avgRadius
=
total
/
circles
.
Count
;
}
else
{
isEnd
=
true
;
}
}
public
List
<
List
<
Circle
>>
groupCircles
(
double
w
,
double
h
,
Point2d
center
)
{
foreach
(
Circle
c
in
circles
)
{
c
.
calDistanceToCenter
(
center
);
}
List
<
List
<
Circle
>>
allGroupCircle
=
new
List
<
List
<
Circle
>>();
List
<
int
>
allreadyGroup
=
new
List
<
int
>();
while
(
true
)
{
List
<
Circle
>
groupCircle
=
new
List
<
Circle
>();
Circle
labelCircle
=
null
;
for
(
int
i
=
0
;
i
<
circles
.
Count
;
i
++)
{
if
(!
allreadyGroup
.
Contains
(
i
))
{
Circle
c
=
circles
[
i
];
if
(
labelCircle
==
null
)
{
labelCircle
=
c
;
allreadyGroup
.
Add
(
i
);
groupCircle
.
Add
(
c
);
}
else
{
//到圆心的距离差小于H
if
(
Math
.
Abs
(
c
.
distanceToCenter
-
labelCircle
.
distanceToCenter
)
<
h
)
{
//两圆心之间的距离+直径小于W认为是同一个元器件
if
(
c
.
distanceToCircle
(
labelCircle
)
<
w
)
{
groupCircle
.
Add
(
c
);
allreadyGroup
.
Add
(
i
);
}
}
}
}
}
allGroupCircle
.
Add
(
groupCircle
);
if
(
allreadyGroup
.
Count
==
circles
.
Count
)
{
break
;
}
}
return
allGroupCircle
;
}
/// <summary>
/// 该点是否与其他圆内,或与圆的中心距离在半径内
/// </summary>
/// <param name="px"></param>
/// <param name="py"></param>
/// <returns></returns>
public
double
minDistanceToCircles
(
int
px
,
int
py
,
Point2d
reelCenter
,
double
oneBlobWidth
=-
1
,
double
oneBlobRadius
=
-
1
)
{
Point2d
point
=
new
Point2d
(
px
,
py
);
double
minDistanceToCircle
=
-
1
;
foreach
(
Circle
c
in
circles
)
{
Point2d
circleCenter
=
new
Point2d
(
c
.
x
,
c
.
y
);
double
distanceToCircle
=
point
.
DistanceTo
(
circleCenter
);
if
(
distanceToCircle
<=
c
.
radius
)
{
return
0
;
}
//当前点到料盘中心与圆心到料盘中心的距离在直径内,忽略
//if(oneBlobRadius != -1 && oneBlobWidth != -1)
//{
// double distanceToReelCenter = point.DistanceTo(reelCenter);
// double circleCenterToReelCenter = circleCenter.DistanceTo(reelCenter);
// if (Math.Abs(distanceToReelCenter - circleCenterToReelCenter) < oneBlobRadius)
// {
// if (distanceToCircle < oneBlobWidth)
// {
// return 0;
// }
// }
//}
if
(
minDistanceToCircle
==
-
1
||
distanceToCircle
<
minDistanceToCircle
)
{
minDistanceToCircle
=
distanceToCircle
-
c
.
radius
;
}
}
return
minDistanceToCircle
;
}
};
public
class
Circle
{
public
int
x
;
public
int
y
;
public
double
radius
;
public
double
distanceToCenter
=
0
;
public
double
distanceToCircle
(
Circle
c
)
{
double
distance
=
new
Point2d
(
x
,
y
).
DistanceTo
(
new
Point2d
(
c
.
x
,
c
.
y
));
return
distance
+
radius
+
c
.
radius
;
}
public
void
calDistanceToCenter
(
Point2d
center
)
{
if
(
center
.
X
>
0
&&
distanceToCenter
<=
0
)
{
distanceToCenter
=
center
.
DistanceTo
(
new
Point2d
(
x
,
y
));
}
}
}
}
Demo/MainForm.cs
查看文件 @
8511f26
...
@@ -69,7 +69,16 @@ namespace Acc.Demo
...
@@ -69,7 +69,16 @@ namespace Acc.Demo
{
{
theshValue
=
int
.
Parse
(
textBoxThesh
.
Text
);
theshValue
=
int
.
Parse
(
textBoxThesh
.
Text
);
}
}
Image
result
=
ImageUtil
.
Threshhold
(
orginalImage
,
theshValue
,
false
);
Image
result
;
result
=
ImageUtil
.
Threshhold
(
orginalImage
,
theshValue
);
//if (theshValue == -1)
//{
// result = ImageUtil.Threshhold(imageBox.Image, theshValue);
//}
//else
//{
// result = ImageUtil.DistanceTransform(imageBox.Image);
//}
imageBox
.
Image
=
result
;
imageBox
.
Image
=
result
;
}
}
...
@@ -105,26 +114,12 @@ namespace Acc.Demo
...
@@ -105,26 +114,12 @@ namespace Acc.Demo
private
void
Count
()
private
void
Count
()
{
{
ClearStatusBar
();
ClearStatusBar
();
int
theshValue
=
-
1
;
if
(!
checkBoxAutoThresh
.
Checked
)
{
theshValue
=
int
.
Parse
(
textBoxThesh
.
Text
);
}
Task
.
Factory
.
StartNew
(
delegate
{
Task
.
Factory
.
StartNew
(
delegate
{
//Image image = ImageUtil.FindCircle(orginalImage, theshValue, inv);
//imageBox.Image = image;
Stopwatch
sw
=
new
Stopwatch
();
Stopwatch
sw
=
new
Stopwatch
();
sw
.
Start
();
sw
.
Start
();
int
itemFeature
=
int
.
Parse
(
textBoxFeature
.
Text
);
int
itemFeature
=
int
.
Parse
(
textBoxFeature
.
Text
);
Image
image
=
orginalImage
;
Image
image
=
orginalImage
;
if
(!
ImageUtil
.
selectB
)
int
count
=
ImageUtil
.
CountItems
(
ref
image
,
itemFeature
);
{
itemFeature
=
ImageUtil
.
GetItemFeatureAuto
(
image
,
markX
,
markY
,
theshValue
);
}
ImageUtil
.
selectB
=
false
;
int
count
=
ImageUtil
.
CountItems
(
ref
image
,
itemFeature
,
theshValue
);
sw
.
Stop
();
sw
.
Stop
();
labelTime
.
Text
=
"耗时:"
+
sw
.
ElapsedMilliseconds
+
" ms"
;
labelTime
.
Text
=
"耗时:"
+
sw
.
ElapsedMilliseconds
+
" ms"
;
labelCount
.
Text
=
"数量:"
+
count
;
labelCount
.
Text
=
"数量:"
+
count
;
...
@@ -152,14 +147,23 @@ namespace Acc.Demo
...
@@ -152,14 +147,23 @@ namespace Acc.Demo
private
void
元件特征
ToolStripMenuItem_Click
(
object
sender
,
EventArgs
e
)
private
void
元件特征
ToolStripMenuItem_Click
(
object
sender
,
EventArgs
e
)
{
{
ClearStatusBar
();
ClearStatusBar
();
int
theshValue
=
-
1
;
Image
image
=
orginalImage
;
if
(!
checkBoxAutoThresh
.
Checked
)
int
feature
=
ImageUtil
.
GetFeature
(
ref
image
,
markX
,
markY
);
{
textBoxFeature
.
Text
=
feature
.
ToString
();
theshValue
=
int
.
Parse
(
textBoxThesh
.
Text
);
}
ImageUtil
.
selectB
=
true
;
Image
image
=
ImageUtil
.
Mark
(
orginalImage
,
markX
,
markY
,
theshValue
);
imageBox
.
Image
=
image
;
imageBox
.
Image
=
image
;
//int theshValue = -1;
//if (!checkBoxAutoThresh.Checked)
//{
// theshValue = int.Parse(textBoxThesh.Text);
//}
//Stopwatch sw = new Stopwatch();
//sw.Start();
//Image image = ImageUtil.Mark(orginalImage, markX, markY, theshValue);
//imageBox.Image = image;
//sw.Stop();
//Console.WriteLine("总耗时:" + sw.ElapsedMilliseconds + " ms");
}
}
private
void
保存当前图片
ToolStripMenuItem_Click
(
object
sender
,
EventArgs
e
)
private
void
保存当前图片
ToolStripMenuItem_Click
(
object
sender
,
EventArgs
e
)
...
...
Demo/MainForm.designer.cs
查看文件 @
8511f26
...
@@ -83,7 +83,7 @@
...
@@ -83,7 +83,7 @@
//
//
this
.
元件特征
ToolStripMenuItem
.
Name
=
"元件特征ToolStripMenuItem"
;
this
.
元件特征
ToolStripMenuItem
.
Name
=
"元件特征ToolStripMenuItem"
;
this
.
元件特征
ToolStripMenuItem
.
Size
=
new
System
.
Drawing
.
Size
(
180
,
22
);
this
.
元件特征
ToolStripMenuItem
.
Size
=
new
System
.
Drawing
.
Size
(
180
,
22
);
this
.
元件特征
ToolStripMenuItem
.
Text
=
"
标记记数
"
;
this
.
元件特征
ToolStripMenuItem
.
Text
=
"
元件特征
"
;
this
.
元件特征
ToolStripMenuItem
.
Click
+=
new
System
.
EventHandler
(
this
.
元件特征
ToolStripMenuItem_Click
);
this
.
元件特征
ToolStripMenuItem
.
Click
+=
new
System
.
EventHandler
(
this
.
元件特征
ToolStripMenuItem_Click
);
//
//
// 计数ToolStripMenuItem
// 计数ToolStripMenuItem
...
...
编写
预览
支持
Markdown
格式
附加文件
你添加了
0
人
到此讨论。请谨慎行事。
Finish editing this message first!
Cancel
请
注册
或
登录
后发表评论