Identify coins and cell number + bar code detection (python+opencv)

1, Preparatory work

  • Pictures used


  • python version and opencv version

python 3.8.12 opencv 3.4.11

2, Coin and cell number recognition

  • principle
  1. Read the picture with opencv. After reading, grayscale and binarization are carried out
  2. After binarization, the values in the two-dimensional list of stored pictures are all 0 and 1. Expand and corrode to make the outline of the image more obvious
  3. Obviously, after using findContours, the number of contours found is the number we require
  • Start the code operation, import the library and define the file path
#Import related packages
import cv2
import numpy as np
import os
#Define file path
source_path='..\\source\\AI_digital_image\\'
cell_file="cell.png"
coin_file="coin.png"
  • Build a complete path and read the picture. I won't put the picture. Just run it and have a look. Forget it, put the picture behind the code and have a look
#Get full path
cell_path=source_path+cell_file
coin_path=source_path+coin_file  
#read file
cell_read=cv2.imread(cell_path)
coin_read=cv2.imread(coin_path)
cv2.imshow("cell",cell_read)
cv2.waitKey(0)

  • First, the number of cells is extracted. Here, it is grayed out, and a wave of brightness is manually adjusted, because the brightness of the picture is inconsistent up and down. If it is not adjusted, the effect of binarization is not very good
#Graying
cell_gauss=cv2.GaussianBlur(cell_read,(5,5),0)#Gaussian noise reduction
cell_gray=cv2.cvtColor(cell_gauss,cv2.COLOR_BGR2GRAY)#Grayscale
cell_att=cell_gray
cv2.waitKey(0)
#The brightness of the upper part is too low, increase it manually
for j in range(3,342):
    low=int(sum(cell_gray[j]))
    high=int(sum(cell_gray[335]))
    add=(high-low)/len(cell_read[3])
    for i in range(len(cell_read[3])):
        if int(cell_att[j][i])+add>255:
             cell_att[j][i]=255
        else :
            cell_att[j][i]+=add
cv2.imshow("cell",cell_att)
cv2.waitKey(0)

  • Binarization
thre,cell_bw=cv2.threshold(cell_att,170,255,cv2.THRESH_BINARY_INV)#Binarization
cv2.imshow("cell",cell_bw)
cv2.waitKey(0)

  • The picture of cells should be a sample of blood. Otherwise, why are there so many red blood cells? The middle of red blood cells is empty. After graying, there will be small holes. First, use closed operation to fill these empty places
#Closed operation, filling holes
#Construct a 5 * 5 matrix of all 1
kernel=np.ones((3,3),int)#Sets the size of morphological operation convolution
cell_close=cv2.morphologyEx(cell_bw,cv2.MORPH_CLOSE,kernel)
cv2.imshow("cell",cell_close)
cv2.waitKey(0)

  • Open operation: used to eliminate small objects, smooth the shape boundary, and do not change its area. It can remove small particle noise and break the adhesion between objects
#Open operation
#Construct a 5 * 5 matrix of all 1
kernel=np.ones((11,11),int)#Sets the size of morphological operation convolution
cell_open=cv2.morphologyEx(cell_close,cv2.MORPH_OPEN,kernel)
cv2.imshow("cell",cell_open)
cv2.waitKey(0)

  • After the operation, corrosion is carried out to enlarge the interval between the two cells, and refine those overlapping places at the same time
#Corrosion operation
#Construct a 5 * 5 matrix of all 1
kernel=np.ones((20,20),int)#Sets the size of morphological operation convolution
cell_corr=cv2.erode(cell_open,kernel,iterations=1)
cv2.imshow("cell",cell_corr)
cv2.waitKey(0)

  • Then open the operation to break the overlapped parts of the thinning
#Open operation
#Construct a 5 * 5 matrix of all 1
kernel=np.ones((10,10),int)#Sets the size of morphological operation convolution
cell_close2=cv2.morphologyEx(cell_corr,cv2.MORPH_OPEN,kernel)
cv2.imshow("cell",cell_close2)
cv2.waitKey(0)

  • Obtain the contour and return the cell by using findcontour of opencv_ Count is the array of contours, and the length is the number of cells. As long as you ask for the number, the contour will be lazy when drawing. Just express a meaning
image,cell_count,hir=cv2.findContours(cell_close2,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
#All contours are detected and a hierarchical tree structure is established for all contours.
print(len(cell_count))
cell_read=cv2.imread(cell_path)
result = cv2.drawContours(cell_read, cell_count, -1 ,(0, 255, 0), 1)
cv2.imshow('I',result)
cv2.waitKey(0)

  • The next step is to detect the number of coins. This is much simpler. It has just been read. Here, graying and binarization are carried out
#Graying and binarization
coin_gauss=cv2.GaussianBlur(coin_read,(5,5),0)#Gaussian noise reduction
coin_gray=cv2.cvtColor(coin_gauss,cv2.COLOR_BGR2GRAY)#Grayscale
thre,coin_bw=cv2.threshold(coin_gray,150,255,cv2.THRESH_BINARY_INV)#Binarization
cv2.imshow("coin",coin_bw)
cv2.waitKey(0)

  • At first, I thought that there would be another open operation. The direct corrosion effect here is very good
#Corrosion operation
#Construct a 5 * 5 matrix of all 1
kernel=np.ones((20,20),int)#Sets the size of morphological operation convolution
coin_corr=cv2.erode(coin_bw,kernel,iterations=1)
cv2.imshow("cell",coin_corr)
cv2.waitKey(0)

  • Get quantity
image,coin_count,hir=cv2.findContours(coin_corr,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
#All contours are detected and a hierarchical tree structure is established for all contours.
print(len(coin_count))
coin_read=cv2.imread(coin_path)
result = cv2.drawContours(coin_read, coin_count, -1 ,(0, 255, 0), 1)
cv2.imshow('I',result)
cv2.waitKey(0)

3, Bar code positioning and identification

  • Positioning does not call the library, which is implemented with opencv
#Import library
import cv2
  • read file
bar_code_path='..\\source\\picture\\bar_code\\code_bar.jpg'
bar_code=cv2.imread(bar_code_path)
bar_code=cv2.resize(bar_code,(500,300))
cv2.imshow('src',bar_code)
cv2.waitKey(0)

  • Convert to grayscale
#Convert to grayscale
bar_code_gray=cv2.cvtColor(bar_code,cv2.COLOR_BGR2GRAY)
cv2.imshow('gray',bar_code_gray)
cv2.waitKey(0)

  • Gaussian smoothing filter
# Gaussian smoothing filter
bar_code_gauss=cv2.GaussianBlur(bar_code_gray,(3,3),0)
cv2.imshow('gauss',bar_code_gauss)
cv2.waitKey(0)

  • Find the difference between horizontal and vertical gradients and use sobel operator. There seems to be some problems with direct subtraction here. It may be that the storage type of opencv in python is different from that in c + +. If it is less than 0, it will become 200 +
#Find the gradient difference between horizontal and vertical directions, using sobel operator
bar_code_h=cv2.Sobel(bar_code_gauss,cv2.CV_64F,1,0,ksize=3,scale=1,delta=0,borderType=4)
bar_code_v=cv2.Sobel(bar_code_gauss,cv2.CV_64F,0,1,ksize=3,scale=1,delta=0,borderType=4)
#Conversion from 16 bits to 8 bits
bar_code_x=cv2.convertScaleAbs(bar_code_h,alpha=1,beta=0)
bar_code_y=cv2.convertScaleAbs(bar_code_v,alpha=1,beta=0)
bar_code_xy=bar_code_x
for i in range(len(bar_code_x)):
    for j in range(len(bar_code_x[0])):
        if int(bar_code_x[i][j])-(bar_code_y[i][j])>=0:
            bar_code_xy[i][j]=bar_code_x[i][j]-bar_code_y[i][j]
        else:
            bar_code_xy[i][j]=0
cv2.imshow('x',bar_code_x)
cv2.waitKey(0)
cv2.imshow('y',bar_code_y)
cv2.waitKey(0)
cv2.imshow('xy',bar_code_xy)
cv2.waitKey(0)



  • Mean filtering
#Mean filtering
bar_code_blur=cv2.blur(bar_code_xy,(3,3))
cv2.imshow('blur',bar_code_blur)
cv2.waitKey(0)

  • Binarization
#Binarization
thr,bar_code_th=cv2.threshold(bar_code_blur,170,255,cv2.THRESH_BINARY)
cv2.imshow('threshold',bar_code_th)
cv2.waitKey(0)

  • Close operation, fill bar code gap
#Close operation, fill bar code gap
import numpy as np
kernel=np.ones((7,7),int)#Sets the size of morphological operation convolution
bar_code_close=cv2.morphologyEx(bar_code_th,cv2.MORPH_CLOSE,kernel)
cv2.imshow('close',bar_code_close)
cv2.waitKey(0)

  • Corrosion, eliminate small white spots next to
#corrosion
kernel=np.ones((7,7),int)#Sets the size of morphological operation convolution
bar_code_ero=cv2.erode(bar_code_close,kernel)
cv2.imshow('erode',bar_code_ero)
cv2.waitKey(0)

  • Expansion connects bar codes
#expand
bar_code_dia=cv2.dilate(bar_code_ero,kernel)
bar_code_dia=cv2.dilate(bar_code_dia,kernel)
bar_code_dia=cv2.dilate(bar_code_dia,kernel)
bar_code_dia=cv2.dilate(bar_code_dia,kernel)
cv2.imshow('dilate',bar_code_dia)
cv2.waitKey(0)

  • Positioning, this deviation is a little confused, which may be caused when calculating the gradient difference
image,barcode,hir=cv2.findContours(bar_code_dia,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
#All contours are detected and a hierarchical tree structure is established for all contours.
barcode_read=cv2.imread(bar_code_path)
result = cv2.drawContours(barcode_read, barcode, -1 ,(0, 255, 0), 1)
cv2.imshow('I',result)
cv2.waitKey(0)

  • If you can identify the barcode, you can check it manually or call the library. Here, you can be lazy and call the pyzbar library
#Call barcode library for barcode recognition
import pyzbar.pyzbar as pyzbar
import cv2
bar_code_path='..\\source\\picture\\bar_code\\code_bar.jpg'
srcImg = cv2.imread(bar_code_path)
cv2.imshow("Image", srcImg)
barcodes = pyzbar.decode(srcImg)
for barcode in barcodes:
    barcodeData = barcode.data.decode("utf-8")
    print(barcodeData)
cv2.waitKey(0)

4, Summary

  • Through the above examples, it is generally understood that the operation of the image is to extract the required elements, then simplify and then simplify, and finally become 0 and 1, and 0 and 1 correspond to black and white, which is very convenient for processing

5, References

Opencv: 10 steps to detect the barcode in the picture
Python opencv detects the number / quantity of eggs in the picture

Tags: Python OpenCV AI Computer Vision

Posted on Sat, 04 Dec 2021 00:52:17 -0500 by said_r3000