基于颜色模式的颜色条形码检测(使用python 2.7和opencv 2.2)
这种颜色条形码有3种颜色:青色,粉色和淡黄色。各种颜色区域为矩形,均匀分布在一个黑底的矩形中。
检测的基本思想是:
1) 如果某个像素属于3种颜色的一种,就把对应坐标处标记为1。
处理完整幅图像后,得到一个2值图像。
2)将1)中得到的2值图像分别向x和y轴投影,也即计算各行和各列的和。
比如:一行为 101111,向y轴投影后,得到的值是5.
投影后,得到x,y轴两个向量。
3)在x和y轴向量中搜索最小和最大的非零值,对应的坐标就圈定了条形码所在位置。
当然这里要设定一个阈值,比如非零值的最小必须大于3或者5之类的,因为矩形颜色块是有最小面积的。
不过,为了能在实际中使用,还需要添加很多处理,比如噪声,颜色变化,视角变化之类的因素也需要考虑。
下面是处理结果的截图,后面有代码:
代码
#!/usr/bin/python
#
#
import cv
import sys
import math
names = ["temp.jpg"];
def findFirstColorPattern(img, pattern):
"""
try to test if one pixel is in our pattern
"""
channels = [None, None, None]
channels[0] = cv.CreateImage(cv.GetSize(img),8,1)#blue
channels[1] = cv.CreateImage(cv.GetSize(img),8,1)#green
channels[2] = cv.CreateImage(cv.GetSize(img),8,1)#red
ch0 = cv.CreateImage(cv.GetSize(img),8,1)#blue
ch1 = cv.CreateImage(cv.GetSize(img),8,1)#green
ch2 = cv.CreateImage(cv.GetSize(img),8,1)#red
cv.Split(img, ch0, ch1, ch2, None)
dest0 = cv.CreateImage(cv.GetSize(img),8,1)
dest1 = cv.CreateImage(cv.GetSize(img),8,1)
dest2 = cv.CreateImage(cv.GetSize(img),8,1)
dest3 = cv.CreateImage(cv.GetSize(img),8,1)
cv.Smooth(ch0, channels[0], cv.CV_GAUSSIAN, 3, 3, 0)
cv.Smooth(ch1, channels[1], cv.CV_GAUSSIAN, 3, 3, 0)
cv.Smooth(ch2, channels[2], cv.CV_GAUSSIAN, 3, 3, 0)
result =[]
for i in range(3):
lower = pattern[i][2] - 25
upper = pattern[i][2] + 25
cv.InRangeS(channels[0],lower,upper,dest0)
lower = pattern[i][1] - 25
upper = pattern[i][1] + 25
cv.InRangeS(channels[1],lower,upper,dest1)
lower = pattern[i][0] - 25
upper = pattern[i][0] + 25
cv.InRangeS(channels[2],lower,upper,dest2)
cv.And(dest0,dest1,dest3)
temp = cv.CreateImage(cv.GetSize(img),8,1)
cv.And(dest2,dest3,temp)
result.append(temp)
cv.Or(result[0],result[1],dest0)
cv.Or(dest0,result[2],dest3)
cv.NamedWindow("result",cv.CV_WINDOW_AUTOSIZE)
cv.ShowImage("result",dest3)
#cv.WaitKey(0)
return dest3
def xyProject(mat,imagesize):
"""
"project" image to x and y axis
"""
colmask =cv.CreateMat(imagesize[1],1,cv.CV_8UC1)
rowmask =cv.CreateMat(1,imagesize[0],cv.CV_8UC1)
cv.Set(colmask,1)
cv.Set(rowmask,1)
colsum=[]
for i in range(imagesize[0]):
col = cv.GetCol(matrix,i)
a = cv.DotProduct(colmask,col)
colsum.append(a)
rowsum =[]
for i in range(imagesize[1]):
row = cv.GetRow(matrix,i)
a = cv.DotProduct(rowmask,row)
rowsum.append(a)
return (colsum,rowsum)
def getMinNonZero(arr):
minv = max(arr)
for a in arr:
if a > 0 and a < minv:
minv = a
return minv
def getMeanDistance(data,minv):
shiftindex = [0]
index=[]
for i in range(len(data)):
if data[i]>minv:
index.append(i)
shiftindex.append(i)
index.append(index[len(index)-1])
dist=[]
for i in range(len(index)):
dist.append(index[i]-shiftindex[i])
maxdist=max(dist)
index=[]
for i in dist:
if i != maxdist and i > 1:
index.append(i)
mdist= sum(index)/len(index)
#print mdist
return mdist
if __name__ == "__main__":
#TODO: robost against illumination change
pattern_colors=[(219,235,102),(213,71,155),(67,170,228)]#pink, cyan, yellow
image = cv.LoadImage(names[0])
imagesize =cv.GetSize(image)
matrix = findFirstColorPattern(image,pattern_colors)
(colsum,rowsum) = xyProject(matrix,imagesize)
# the following code is trying to find the edge of the small color rectangles
rx0 = 0
minv1 = getMinNonZero(colsum)
for a in colsum:
if a > minv1:
break
rx0 += 1
minv2 = getMinNonZero(rowsum)
ry0 = 0
for a in rowsum:
if a > minv2:
break
ry0 += 1
arrlen = len(colsum)
rx1 = arrlen -1
for i in range(arrlen):
if colsum[arrlen-1-i] > minv1:
break
rx1 -= 1
arrlen = len(rowsum)
ry1 = arrlen -1
for i in range(arrlen):
if rowsum[arrlen-1-i] > minv2:
break
ry1 -= 1
# try to compute the mean distance between two small color rectangles
mdist = getMeanDistance(colsum,minv1)
rectx0 = rx0-mdist*2
recty0 = ry0-mdist*2
if rectx0 < 0:
rectx0 = 0
if recty0 < 0:
recty0 = 0
rectx1 = rx1+mdist*2
if rectx1 > imagesize[0]:
rectx1 = imagesize[0]
recty1 = ry1+mdist*2
if recty1 > imagesize[1]:
recty1 = imagesize[1]
#cv.Circle(image,(int(rx0),int(ry0)),5,cv.CV_RGB(0,255,0))
#cv.Circle(image,(int(rx1),int(ry1)),5,cv.CV_RGB(0,255,0))
roi = cv.GetSubRect(image,(rectx0,recty0,rectx1-rectx0,recty1-recty0))
pt=[(rectx0,recty0),(rectx1,recty0),(rectx1,recty1),(rectx0,recty1)]
cv.PolyLine( image, [pt], 1, cv.CV_RGB(0,255,0), 3, cv.CV_AA, 0 );
cv.NamedWindow("test",cv.CV_WINDOW_AUTOSIZE)
cv.ShowImage("test",image)
cv.NamedWindow("roi",cv.CV_WINDOW_AUTOSIZE)
cv.ShowImage("roi",roi)
cv.SaveImage("result.png",image)
cv.WaitKey(0)
cv.DestroyWindow("test")
cv.DestroyWindow("result")
cv.DestroyWindow("roi")
转载请注明出处