考虑这10张不同数量的白米未煮谷物的图片。
这些只是缩略图。单击图像以查看完整大小的图像。
答:

B:

C:

D:

E:

F:

G:

H:

我:

J:

谷物计数:A: 3, B: 5, C: 12, D: 25, E: 50, F: 83, G: 120, H:150, I: 151, J: 200
注意到..。
这5点是所有这类图像的保证。
编写一个程序,接收这样的图像,并尽可能准确地计算稻谷的数量。
您的程序应该获取图像的文件名,并打印它计算出来的颗粒数。您的程序必须至少为这些图像文件格式中的一种工作: JPEG、Bitmap、PNG、GIF、TIFF (现在这些图像都是JPEG格式)。
您可以使用图像处理和计算机视觉库。
您可能不会硬编码10个示例图像的输出。你的算法应该适用于所有类似的稻谷图像。如果图像面积小于2000*2000像素,并且有不到300粒大米,它应该能够在像样的现代计算机上运行不到5分钟。
对于这10幅图像中的每一幅,都取实际颗粒数减去程序预测的颗粒数的绝对值。把这些绝对值加起来,得到你的分数。得分最低者获胜。0的分数是完美的。
如果结果是平局,最高投票的答案将获胜。我可以在额外的图像上测试你的程序,以验证它的有效性和准确性。
发布于 2014-11-03 16:54:02
i = {"http://i.stack.imgur.com/8T6W2.jpg", "http://i.stack.imgur.com/pgWt1.jpg",
"http://i.stack.imgur.com/M0K5w.jpg", "http://i.stack.imgur.com/eUFNo.jpg",
"http://i.stack.imgur.com/2TFdi.jpg", "http://i.stack.imgur.com/wX48v.jpg",
"http://i.stack.imgur.com/eXCGt.jpg", "http://i.stack.imgur.com/9na4J.jpg",
"http://i.stack.imgur.com/UMP9V.jpg", "http://i.stack.imgur.com/nP3Hr.jpg"};
im = Import /@ i;我认为这些函数的名称有足够的描述性:
getSatHSVChannelAndBinarize[i_Image] := Binarize@ColorSeparate[i, "HSB"][[2]]
removeSmallNoise[i_Image] := DeleteSmallComponents[i, 100]
fillSmallHoles[i_Image] := Closing[i, 1]
getMorphologicalComponentsAreas[i_Image] := ComponentMeasurements[i, "Area"][[All, 2]]
roundAreaSizeToGrainCount[areaSize_, grainSize_] := Round[areaSize/grainSize]同时处理所有图片:
counts = Plus @@@
(roundAreaSizeToGrainCount[#, 2900] & /@
(getMorphologicalComponentsAreas@
fillSmallHoles@
removeSmallNoise@
getSatHSVChannelAndBinarize@#) & /@ im)
(* Output {3, 5, 12, 25, 49, 83, 118, 149, 152, 202} *)得分是:
counts - {3, 5, 12, 25, 50, 83, 120, 150, 151, 200} // Abs // Total
(* 7 *)在这里,您可以看到分数敏感性wrt所使用的晶粒大小:

发布于 2014-11-03 21:49:42
得分27
想法:扫描图像,一次只扫描一行。对于每一行,计算遇到的米粒数(检查像素是变黑到白还是相反)。如果这条线的谷物数量增加(与前一行相比),那就意味着我们遇到了一个新的谷物。如果这个数字减少,就意味着我们通过了一颗谷物。在这种情况下,将+1添加到总结果中。

Number in red = rice grains encountered for that line
Number in gray = total amount of grains encountered (what we are looking for)由于算法的工作方式,有一个干净的,b/w图像是很重要的。许多噪音会产生不好的结果。首先使用洪水(类似于Ell应答的溶液)清除主背景,然后应用阈值产生黑白结果。

它远非完美,但在简单性方面却产生了良好的效果。可能有很多方法来改进它(通过提供更好的b/w图像,在其他方向(例如:垂直、对角线)扫描平均值等.)
import cv2
import numpy
import sys
filename = sys.argv[1]
I = cv2.imread(filename, 0)
h,w = I.shape[:2]
diff = (3,3,3)
mask = numpy.zeros((h+2,w+2),numpy.uint8)
cv2.floodFill(I,mask,(0,0), (255,255,255),diff,diff)
T,I = cv2.threshold(I,180,255,cv2.THRESH_BINARY)
I = cv2.medianBlur(I, 7)
totalrice = 0
oldlinecount = 0
for y in range(0, h):
oldc = 0
linecount = 0
start = 0
for x in range(0, w):
c = I[y,x] < 128;
if c == 1 and oldc == 0:
start = x
if c == 0 and oldc == 1 and (x - start) > 10:
linecount += 1
oldc = c
if oldlinecount != linecount:
if linecount < oldlinecount:
totalrice += oldlinecount - linecount
oldlinecount = linecount
print totalrice每个图像的错误: 0,0,0,3,0,12,4,0,7,1
发布于 2014-11-02 09:03:50
这是第一次天真的尝试。它采用了人工调节参数的自适应阈值,关闭了一些随后发生腐蚀和稀释的洞,并从前景区域推导出晶粒数。
import cv2
import numpy as np
filename = raw_input()
I = cv2.imread(filename, 0)
I = cv2.medianBlur(I, 3)
bw = cv2.adaptiveThreshold(I, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 101, 1)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (17, 17))
bw = cv2.dilate(cv2.erode(bw, kernel), kernel)
print np.round_(np.sum(bw == 0) / 3015.0)在这里,您可以看到中间的二进制图像(黑色是前景):

每幅图像的误差分别为0、0、2、2、4、0、27、42、0和7粒。
https://codegolf.stackexchange.com/questions/40831
复制相似问题