qingkuangs 发表于 2015-4-24 07:25:43

基于颜色模式的颜色条形码检测(使用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 =
    channels = cv.CreateImage(cv.GetSize(img),8,1)#blue
    channels = cv.CreateImage(cv.GetSize(img),8,1)#green
    channels = 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, cv.CV_GAUSSIAN, 3, 3, 0)
    cv.Smooth(ch1, channels, cv.CV_GAUSSIAN, 3, 3, 0)
    cv.Smooth(ch2, channels, cv.CV_GAUSSIAN, 3, 3, 0)
    result=[]
    for i in range(3):
      lower = pattern - 25
      upper = pattern + 25
      cv.InRangeS(channels,lower,upper,dest0)      
      lower = pattern - 25
      upper = pattern + 25
      cv.InRangeS(channels,lower,upper,dest1)
      lower = pattern - 25
      upper = pattern + 25      
      cv.InRangeS(channels,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,result,dest0)
    cv.Or(dest0,result,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,cv.CV_8UC1)
    rowmask    =cv.CreateMat(1,imagesize,cv.CV_8UC1)
    cv.Set(colmask,1)
    cv.Set(rowmask,1)
    colsum=[]
    for i in range(imagesize):
      col = cv.GetCol(matrix,i)
      a = cv.DotProduct(colmask,col)
      colsum.append(a)
    rowsum =[]
    for i in range(imagesize):
      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 =
    index=[]
    for i in range(len(data)):
      if data>minv:
            index.append(i)
            shiftindex.append(i)
    index.append(index)
    dist=[]
    for i in range(len(index)):
            dist.append(index-shiftindex)
    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)
    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 > minv1:
            break
      rx1 -= 1
    arrlen = len(rowsum)
    ry1 = arrlen -1
    for i in range(arrlen):
      if rowsum > 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:
      rectx1 = imagesize
    recty1 = ry1+mdist*2
    if recty1 > imagesize:
      recty1 = imagesize
    #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, , 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")
  


  
页: [1]
查看完整版本: 基于颜色模式的颜色条形码检测(使用python 2.7和opencv 2.2)