图像处理方法
Image processing approach
在下面的灰度图像中,我试图识别我手动标记为红色的对象。有人对如何执行此操作有建议吗?
我曾尝试使用高斯模糊和阈值处理,但无法完全识别这些粒子。边缘检测会是一个好方法吗?欢迎任何建议。
我只是从 command-line 使用 ImageMagick 快速完成了此操作。我确信可以通过查看检测到的 blob 的 squareness
来改进它,但我没有无限的可用时间,你说欢迎任何想法......
首先,我对图像进行了阈值处理,然后我将每个像素替换为水平行中左右各 6 个像素的最大像素 - 这是将每个咖啡豆形状的两半连接在一起。命令是这样的:
convert http://i.stack.imgur.com/mr0OM.jpg -threshold 80% -statistic maximum 13x1 w.jpg
看起来像这样:
然后我在上面添加了一个连通分量分析来找到斑点,像这样:
convert http://i.stack.imgur.com/mr0OM.jpg \
-threshold 80% -statistic maximum 13x1 \
-define connected-components:verbose=true \
-define connected-components:area-threshold=500 \
-connected-components 8 -auto-level output.png
Objects (id: bounding-box centroid area mean-color):
0: 1280x1024+0+0 642.2,509.7 1270483 srgb(4,4,4)
151: 30x303+137+712 152.0,863.7 5669 srgb(255,255,255)
185: 29x124+410+852 421.2,913.2 2281 srgb(255,255,255)
43: 48x48+445+247 467.9,271.5 1742 srgb(255,255,255)
35: 21x94+234+214 243.7,259.2 1605 srgb(255,255,255)
10: 52x49+183+31 209.9,56.2 1601 srgb(255,255,255)
30: 31x86+504+176 523.1,217.2 1454 srgb(255,255,255)
171: 61x39+820+805 856.0,825.7 1294 srgb(255,255,255)
119: 20x78+1212+625 1221.6,664.3 1277 srgb(255,255,255)
17: 44x40+587+106 608.3,124.9 1267 srgb(255,255,255)
94: 19x70+1077+545 1086.1,580.6 1100 srgb(255,255,255)
59: 43x33+947+329 967.4,344.3 1092 srgb(255,255,255)
40: 39x32+735+235 754.4,251.0 1074 srgb(255,255,255)
91: 22x62+1258+540 1268.3,571.0 1045 srgb(255,255,255)
18: 23x50+197+124 207.1,148.1 996 srgb(255,255,255)
28: 40x28+956+165 976.8,177.7 970 srgb(255,255,255)
76: 22x55+865+467 875.6,493.8 955 srgb(255,255,255)
187: 18x59+236+858 244.4,886.4 928 srgb(255,255,255)
211: 46x27+720+997 743.8,1009.0 891 srgb(255,255,255)
206: 19x47+418+977 427.5,1000.5 804 srgb(255,255,255)
57: 21x44+231+313 241.4,335.5 769 srgb(255,255,255)
97: 20x45+1215+553 1224.3,574.3 766 srgb(255,255,255)
52: 19x47+516+293 525.4,316.2 752 srgb(255,255,255)
129: 20x41+18+645 28.2,665.1 746 srgb(255,255,255)
83: 21x45+1079+497 1088.1,518.9 746 srgb(255,255,255)
84: 17x44+636+514 644.0,535.7 704 srgb(255,255,255)
62: 19x43+514+348 523.3,369.3 704 srgb(255,255,255)
201: 19x42+233+951 242.3,971.8 675 srgb(255,255,255)
134: 21x39+875+659 884.3,676.9 667 srgb(255,255,255)
194: 25x32+498+910 509.5,924.6 625 srgb(255,255,255)
78: 19x38+459+483 467.8,501.8 622 srgb(255,255,255)
100: 20x37+21+572 30.6,589.4 615 srgb(255,255,255)
53: 18x37+702+296 710.5,314.5 588 srgb(255,255,255)
154: 18x37+1182+723 1191.2,741.3 566 srgb(255,255,255)
181: 47x18+808+842 827.6,850.4 565 srgb(255,255,255)
80: 19x33+525+486 534.2,501.9 544 srgb(255,255,255)
85: 17x34+611+517 618.9,533.4 527 srgb(255,255,255)
203: 21x31+51+960 60.5,974.6 508 srgb(255,255,255)
177: 19x30+692+827 700.7,841.5 503 srgb(255,255,255)
它向我展示了它找到的所有斑点、它们的边界和质心。然后我让 ImageMagick 将检测到的框绘制到您的图像上,如下所示:
为了解释输出,每行代表一个 blob。再来看第二行,即:
151: 30x303+137+712 152.0,863.7 5669 srgb(255,255,255)
这意味着斑点宽 30 像素,高 303 像素,距离图像左侧 137 像素,距离顶部向下 712 像素。所以它基本上是图像左下方最高的绿色框。 152,863是其质心的x,y坐标,面积为5,669像素,颜色为白色。
正如我所说,它可以改进,可能是通过查看斑点边的比例来找到方形,但它可能会给你一些想法。顺便说一下,你能说出这些斑点是什么吗?
我给出了以下算法。在对 OP 问题的评论中,但它是一个简短的片段,所以为什么不用 python 给出 opencv 的书面答案。
希望这比 Mark Setchell 的回答更具可扩展性,并且更符合 OP 的标签。
import cv2
import numpy as np
img = cv2.imread("a.jpg", cv2.IMREAD_GRAYSCALE)
ret,thresh = cv2.threshold(img,127,255,0)
contours,hierarchy = cv2.findContours(thresh, 1, 2)
#color image for testing purposes
color = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
for cnt in contours:
x,y,w,h = cv2.boundingRect(cnt)
if w>h: delta = w/h
else: delta = h/w
if delta<4 and w>10 and h>10:
cv2.rectangle(color,(x,y),(x+w,y+h),(0,0,255),2)
cv2.imwrite("c.jpg", color)
它提供了 6-7 个额外的小对象,这些对象是错误检测。然而,这可以通过使用我提到的 erode
和 dilate
函数以及可能将 treshold
切换为 canny
边缘检测算法来轻松改进。可以通过要求更长的矩形宽度和长度来解决错误检测。
更新代码
只是为了炫耀一些您可以玩的额外选项。
import cv2
import numpy as np
img = cv2.imread("a.jpg", cv2.IMREAD_GRAYSCALE)
img[np.where(img<100)] = 0 #set all pixels with intensities bellow 100 to 0
img[(img>100) & (img<244)] += 10 #same as above, set all other pixels>100 and smaller than 254 (when you add 10) to be more "white" than before, exaggerating objects
img = cv2.equalizeHist(img) #just for good measure I suppose?
#matrices filled with '1' everywhere, different dimensions
erode_kernel = np.ones((4,4))
dilate_kernel = np.ones((9,9))
small_dilate_kernel = np.ones((2,2))
erode = cv2.erode(img, erode_kernel)
dilate = cv2.dilate(erode, dilate_kernel)
canny = cv2.Canny(dilate, 180, 255) #if pixel value is not in range 180-255 it is not considered for edge detection
canny = cv2.dilate(canny, small_dilate_kernel) #just to combine close edges to make them appear as a single edge, might be a bad idea
contours,hierarchy = cv2.findContours(canny, cv2.RETR_EXTERNAL, #retr_exernal ignores all inside-object features and returns just the outside-most contours
cv2.CHAIN_APPROX_NONE)
a = np.zeros(img.shape) #test image to see what happened so far
cv2.drawContours(a, contours, -1, (255,255,255), 1)
cv2.imwrite("contours.jpg", a)
#color image for testing purposes
color = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
for cnt in contours:
x,y,w,h = cv2.boundingRect(cnt)
if w>h: delta = w/h
else: delta = h/w
if delta<4 and w>20 and h>20:
cv2.rectangle(color,(x,y),(x+w,y+h),(0,0,255),2)
cv2.imwrite("c.jpg", color)
祝你好运,比赛。视觉需要大量的摆弄才能让它按照你想要的方式工作。花点时间阅读手册。重叠的东西很难设置,因为我们现在正在尽最大努力将它们组合在一起作为一个单一的对象。
如果你能让咖啡豆显示为圆圈,你可以尝试使用 HoughCircle
检测。但是看到它们相当不规则,我不太确定这是最好的方法。训练你自己的 haar 级联可能是你最好的选择,但我以前从未做过,所以在这方面我帮不上什么忙。
您的图片看起来适合机器学习。
- 我使用 Trainable Weka 创建了以下概率图
ImageJ/Fiji 的分割插件(以你的第二张图片作为输入):
您应该能够通过简单的阈值处理和可能的一些后续大小过滤来获取对象。
- 您可能还想尝试 ilastik,一款免费软件
将 像素分类 和 对象跟踪 与所有
机器学习的力量。
编辑:
这就是我使用 Trainable Weka 分割的方式:
- 在设置中window,我激活了一些更多的功能,设置
sigma 范围从 4 到 32,并命名为 类 "Objects" 和
"Background":
- 然后我创建了一些手绘线迹,将它们添加到相应的 类,然后单击 "Train classifier"。 (第一次 运行 训练时,特征堆栈的创建需要一些时间,但细化分类花费的时间更少,因为只有分类需要 运行。)
- 要获取概率图,请单击 "Get probability"。
感谢所有建议。我研究了很多解决这个问题的方法,我得到的最好结果是使用 opencv 和 haar 之类的特征级联分类。
我遵循了这个教程,并取得了很高的准确性:
http://coding-robin.de/2013/07/22/train-your-own-opencv-haar-classifier.html
这是前两张图片的结果,通过对分类器进行一些优化,可以进一步改进:
在下面的灰度图像中,我试图识别我手动标记为红色的对象。有人对如何执行此操作有建议吗?
我曾尝试使用高斯模糊和阈值处理,但无法完全识别这些粒子。边缘检测会是一个好方法吗?欢迎任何建议。
我只是从 command-line 使用 ImageMagick 快速完成了此操作。我确信可以通过查看检测到的 blob 的 squareness
来改进它,但我没有无限的可用时间,你说欢迎任何想法......
首先,我对图像进行了阈值处理,然后我将每个像素替换为水平行中左右各 6 个像素的最大像素 - 这是将每个咖啡豆形状的两半连接在一起。命令是这样的:
convert http://i.stack.imgur.com/mr0OM.jpg -threshold 80% -statistic maximum 13x1 w.jpg
看起来像这样:
然后我在上面添加了一个连通分量分析来找到斑点,像这样:
convert http://i.stack.imgur.com/mr0OM.jpg \
-threshold 80% -statistic maximum 13x1 \
-define connected-components:verbose=true \
-define connected-components:area-threshold=500 \
-connected-components 8 -auto-level output.png
Objects (id: bounding-box centroid area mean-color):
0: 1280x1024+0+0 642.2,509.7 1270483 srgb(4,4,4)
151: 30x303+137+712 152.0,863.7 5669 srgb(255,255,255)
185: 29x124+410+852 421.2,913.2 2281 srgb(255,255,255)
43: 48x48+445+247 467.9,271.5 1742 srgb(255,255,255)
35: 21x94+234+214 243.7,259.2 1605 srgb(255,255,255)
10: 52x49+183+31 209.9,56.2 1601 srgb(255,255,255)
30: 31x86+504+176 523.1,217.2 1454 srgb(255,255,255)
171: 61x39+820+805 856.0,825.7 1294 srgb(255,255,255)
119: 20x78+1212+625 1221.6,664.3 1277 srgb(255,255,255)
17: 44x40+587+106 608.3,124.9 1267 srgb(255,255,255)
94: 19x70+1077+545 1086.1,580.6 1100 srgb(255,255,255)
59: 43x33+947+329 967.4,344.3 1092 srgb(255,255,255)
40: 39x32+735+235 754.4,251.0 1074 srgb(255,255,255)
91: 22x62+1258+540 1268.3,571.0 1045 srgb(255,255,255)
18: 23x50+197+124 207.1,148.1 996 srgb(255,255,255)
28: 40x28+956+165 976.8,177.7 970 srgb(255,255,255)
76: 22x55+865+467 875.6,493.8 955 srgb(255,255,255)
187: 18x59+236+858 244.4,886.4 928 srgb(255,255,255)
211: 46x27+720+997 743.8,1009.0 891 srgb(255,255,255)
206: 19x47+418+977 427.5,1000.5 804 srgb(255,255,255)
57: 21x44+231+313 241.4,335.5 769 srgb(255,255,255)
97: 20x45+1215+553 1224.3,574.3 766 srgb(255,255,255)
52: 19x47+516+293 525.4,316.2 752 srgb(255,255,255)
129: 20x41+18+645 28.2,665.1 746 srgb(255,255,255)
83: 21x45+1079+497 1088.1,518.9 746 srgb(255,255,255)
84: 17x44+636+514 644.0,535.7 704 srgb(255,255,255)
62: 19x43+514+348 523.3,369.3 704 srgb(255,255,255)
201: 19x42+233+951 242.3,971.8 675 srgb(255,255,255)
134: 21x39+875+659 884.3,676.9 667 srgb(255,255,255)
194: 25x32+498+910 509.5,924.6 625 srgb(255,255,255)
78: 19x38+459+483 467.8,501.8 622 srgb(255,255,255)
100: 20x37+21+572 30.6,589.4 615 srgb(255,255,255)
53: 18x37+702+296 710.5,314.5 588 srgb(255,255,255)
154: 18x37+1182+723 1191.2,741.3 566 srgb(255,255,255)
181: 47x18+808+842 827.6,850.4 565 srgb(255,255,255)
80: 19x33+525+486 534.2,501.9 544 srgb(255,255,255)
85: 17x34+611+517 618.9,533.4 527 srgb(255,255,255)
203: 21x31+51+960 60.5,974.6 508 srgb(255,255,255)
177: 19x30+692+827 700.7,841.5 503 srgb(255,255,255)
它向我展示了它找到的所有斑点、它们的边界和质心。然后我让 ImageMagick 将检测到的框绘制到您的图像上,如下所示:
为了解释输出,每行代表一个 blob。再来看第二行,即:
151: 30x303+137+712 152.0,863.7 5669 srgb(255,255,255)
这意味着斑点宽 30 像素,高 303 像素,距离图像左侧 137 像素,距离顶部向下 712 像素。所以它基本上是图像左下方最高的绿色框。 152,863是其质心的x,y坐标,面积为5,669像素,颜色为白色。
正如我所说,它可以改进,可能是通过查看斑点边的比例来找到方形,但它可能会给你一些想法。顺便说一下,你能说出这些斑点是什么吗?
我给出了以下算法。在对 OP 问题的评论中,但它是一个简短的片段,所以为什么不用 python 给出 opencv 的书面答案。
希望这比 Mark Setchell 的回答更具可扩展性,并且更符合 OP 的标签。
import cv2
import numpy as np
img = cv2.imread("a.jpg", cv2.IMREAD_GRAYSCALE)
ret,thresh = cv2.threshold(img,127,255,0)
contours,hierarchy = cv2.findContours(thresh, 1, 2)
#color image for testing purposes
color = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
for cnt in contours:
x,y,w,h = cv2.boundingRect(cnt)
if w>h: delta = w/h
else: delta = h/w
if delta<4 and w>10 and h>10:
cv2.rectangle(color,(x,y),(x+w,y+h),(0,0,255),2)
cv2.imwrite("c.jpg", color)
它提供了 6-7 个额外的小对象,这些对象是错误检测。然而,这可以通过使用我提到的 erode
和 dilate
函数以及可能将 treshold
切换为 canny
边缘检测算法来轻松改进。可以通过要求更长的矩形宽度和长度来解决错误检测。
更新代码
只是为了炫耀一些您可以玩的额外选项。
import cv2
import numpy as np
img = cv2.imread("a.jpg", cv2.IMREAD_GRAYSCALE)
img[np.where(img<100)] = 0 #set all pixels with intensities bellow 100 to 0
img[(img>100) & (img<244)] += 10 #same as above, set all other pixels>100 and smaller than 254 (when you add 10) to be more "white" than before, exaggerating objects
img = cv2.equalizeHist(img) #just for good measure I suppose?
#matrices filled with '1' everywhere, different dimensions
erode_kernel = np.ones((4,4))
dilate_kernel = np.ones((9,9))
small_dilate_kernel = np.ones((2,2))
erode = cv2.erode(img, erode_kernel)
dilate = cv2.dilate(erode, dilate_kernel)
canny = cv2.Canny(dilate, 180, 255) #if pixel value is not in range 180-255 it is not considered for edge detection
canny = cv2.dilate(canny, small_dilate_kernel) #just to combine close edges to make them appear as a single edge, might be a bad idea
contours,hierarchy = cv2.findContours(canny, cv2.RETR_EXTERNAL, #retr_exernal ignores all inside-object features and returns just the outside-most contours
cv2.CHAIN_APPROX_NONE)
a = np.zeros(img.shape) #test image to see what happened so far
cv2.drawContours(a, contours, -1, (255,255,255), 1)
cv2.imwrite("contours.jpg", a)
#color image for testing purposes
color = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
for cnt in contours:
x,y,w,h = cv2.boundingRect(cnt)
if w>h: delta = w/h
else: delta = h/w
if delta<4 and w>20 and h>20:
cv2.rectangle(color,(x,y),(x+w,y+h),(0,0,255),2)
cv2.imwrite("c.jpg", color)
祝你好运,比赛。视觉需要大量的摆弄才能让它按照你想要的方式工作。花点时间阅读手册。重叠的东西很难设置,因为我们现在正在尽最大努力将它们组合在一起作为一个单一的对象。
如果你能让咖啡豆显示为圆圈,你可以尝试使用 HoughCircle
检测。但是看到它们相当不规则,我不太确定这是最好的方法。训练你自己的 haar 级联可能是你最好的选择,但我以前从未做过,所以在这方面我帮不上什么忙。
您的图片看起来适合机器学习。
- 我使用 Trainable Weka 创建了以下概率图 ImageJ/Fiji 的分割插件(以你的第二张图片作为输入):
您应该能够通过简单的阈值处理和可能的一些后续大小过滤来获取对象。
- 您可能还想尝试 ilastik,一款免费软件 将 像素分类 和 对象跟踪 与所有 机器学习的力量。
编辑:
这就是我使用 Trainable Weka 分割的方式:
- 在设置中window,我激活了一些更多的功能,设置 sigma 范围从 4 到 32,并命名为 类 "Objects" 和 "Background":
- 然后我创建了一些手绘线迹,将它们添加到相应的 类,然后单击 "Train classifier"。 (第一次 运行 训练时,特征堆栈的创建需要一些时间,但细化分类花费的时间更少,因为只有分类需要 运行。)
- 要获取概率图,请单击 "Get probability"。
感谢所有建议。我研究了很多解决这个问题的方法,我得到的最好结果是使用 opencv 和 haar 之类的特征级联分类。
我遵循了这个教程,并取得了很高的准确性:
http://coding-robin.de/2013/07/22/train-your-own-opencv-haar-classifier.html
这是前两张图片的结果,通过对分类器进行一些优化,可以进一步改进: