2.5

# Find the Finder

Austin Coates

Recently I was tasked with finding a QR code in an image and then computing its location and. I learned that the first step in locating a QR code is discerning the finder points.  In QR codes there are three finder points located at the furthest reaches of three of the corners.  These finder points are made up of white and black pixels and regardless of the rotation of the code, a cross-section of one finder point will look like the following.

B W B B B W B

B = Black pixel; W = White pixel With this pattern of points being fixed and the ratio of ring counts, with respect to the center block, being for the outer black ring, for the inner, white ring, I found that it was possible to use the contour procedure and a little math to pull out these finder points. Figure 1: Input Image

To locate the finder points, I first opened the image and stripped out a single band.  Then I converted the image to a binary image and coded any gaps that were formed by the conversion.

; open envi

e = envi()

; open the image

oRaster = e.openRaster(inputfile)

; strip out single band

band1 = oRaster.GetData(Bands=0)

; convert to binary image

data = band1 gt 128

; close gaps

data =MORPH_Open(data, REPLICATE(1,3,3)) Figure 2: Binary image

Once I had a binary image, I computed the contour lines for the full image. I then added each contour line to the previous contour line. This step results in an image where contours that overlap have a much higher value than those that do not.

; get the contours of the image

contour, data, PATH_INFO=path_info, path_xy=path_xy,\$

/PATH_DATA_COORDS, LEVELS=[0,1]

; build overlapping image

overlap_img = bytarr(oRaster.ns, oRaster.nl)

; create a container for the ROIs, we will use them again

oROIs = make_array(n_elements(path_info), /OBJ)

for i = 0 , n_elements(path_info)-1 do begin

; get the end pos

end_pos = (path_info[i].offset) + (path_info[i].n)-1

; get the points

pts = path_xy[*,(path_info[i].offset):end_pos]

; last point has to be the same as the first

xs = [[pts[0,*]],[pts[0,0]]]

ys = [[pts[1,*]],[pts[1,0]]]

; create the ROI

oROIs[i] = OBJ_NEW('IDLanROI', xs, ys)

oRaster.nl],\$

; convert to binary

endfor Figure 3: Overlapping contour image

Once the overlapping image was created, I searched for regions that satisfy the and ring ratio rule. If any contour groups were found, the center of mass of each grouping was recorded.

; get the max number of overlaps in the image

max_overlap = max(overlap_img)

; set the desired ratios

desired_ratio1 = 2. + (2./3.)

desired_ratio2 = 1. + (7./9.)

; create a container for the finder points

finder_cm = []

for i = 0 , n_elements(path_info)-1 do begin

oRaster.nl],\$

; convert to binary

;compute the histogram of the image

Hist = HISTOGRAM(StudyArea, LOCATIONS=pos, NBINS=nbins, BINSIZE = 1, MIN=1,\$

MAX=max_overlap)

; if there are more or less than 3 values, then discard it

pos = where(Hist ne 0)

if n_elements(pos) eq 3 then begin

; get the counts for each bin

vals = float(hist[pos])

;calculate the ratios

;outer black ring / inner

ratio1 =  vals / vals

;white ring / inner

ratio2 = vals / vals

; check that the difference is desired ratio

ratio1_dif_percent = ratio1 / desired_ratio1

ratio1_dif_percent = abs(ratio1_dif_percent - 1.)

ratio2_dif_percent = ratio2 / desired_ratio2

ratio2_dif_percent = abs(ratio2_dif_percent - 1.)

; if they are within 60%, save as a finder point

if ratio1_dif_percent lt .3 and ratio2_dif_percent lt .3 then begin

; calculate the center of mass

StudyArea = StudyArea gt 0

Mass = Total(StudyArea)

center_x = Total( Total(StudyArea, 2) * Indgen(oRaster.ns) ) / Mass

center_y = Total( Total(StudyArea, 1) * Indgen(oRaster.nl) ) / Mass

; record the center

finder_cm = [[finder_cm],[center_x,center_y]]

endif

endif

endfor

Last, but not least, I took a moment to plot the results and admire the fruits of my labor.

; display the input image

im = image(oRaster.GetData(interleave='bsq') )

; plot the location of the finder points on top of the input image

for i = 0 ,n_elements(finder_cm[0,*])-1 do \$

p = SCATTERPLOT(finder_cm[0,i],finder_cm[1,i],\$

OVERPLOT = im, AXIS_STYLE=0, SYM_COLOR='red',\$

SYM_FILL_COLOR='blue', SYM_FILLED=0, SYM_SIZE=2,\$

SYMBOL='o',SYM_THICK=4) Figure 4: Final results

I hope that you got something out of this demo. If not how to locate a finder point, then perhaps how to use contours in a new and exciting way.

MOST RECENT

### Cost-effectively Converting Legacy IDL Desktop Applications to Enterprise Applications

9/17/2021

Porting your IDL® application to an enterprise or cloud-based system can seem... more »

### NovaSAR-1 is Almost Here – Enhancing Remote Sensing Applications

9/8/2021

Synthetic Aperture Radar (SAR) is rapidly becoming a fundamental and critical dataset in geospatial... more »