Skip to content

定位点搜寻

原文链接: https://www.nv5geospatialsoftware.com/Learn/Blogs/Blog-Details/find-the-finder

14065 为本文评分:

3.3

定位点搜寻

匿名作者 2016年4月7日,星期四

最近我接到一项任务,需要在图像中寻找一个QR码并计算其位置。我了解到定位QR码的第一步是识别其定位点。QR码中有三个定位点,分别位于其中三个角落的最远端。这些定位点由黑白像素组成,无论QR码如何旋转,一个定位点的横截面看起来都如下所示:

B W B B B W B

B = 黑色像素; W = 白色像素

由于这种点阵模式是固定的,并且相对于中心块,外层黑色环与内层白色环的像素数量比为,我发现可以利用 轮廓程序 和一点数学知识来提取这些定位点。

图 1: 输入图像

为了定位这些定位点,我首先打开图像并提取了单个波段。然后将图像转换为二值图像,并填补了转换过程中形成的任何间隙。

; 打开ENVI
e = envi()

; 打开图像
oRaster = e.openRaster(inputfile)

; 提取单波段
band1 = oRaster.GetData(Bands=0)

; 转换为二值图像
data = band1 gt 128
; 闭合间隙
data = MORPH_Open(data, REPLICATE(1,3,3))

图 2: 二值图像

获得二值图像后,我计算了整个图像的轮廓线。然后,我将每条轮廓线与之前的轮廓线叠加。这一步产生了一幅图像,其中重叠的轮廓区域具有远高于非重叠区域的值。

; 获取图像的轮廓
contour, data, PATH_INFO=path_info, path_xy=path_xy, $
  /PATH_DATA_COORDS, LEVELS=[0,1]

; 构建叠加图像
overlap_img = bytarr(oRaster.ns, oRaster.nl)

; 为ROI创建容器,稍后我们会再次用到它们
oROIs = make_array(n_elements(path_info), /OBJ)

for i = 0 , n_elements(path_info)-1 do begin
  ; 获取结束位置
  end_pos = (path_info[i].offset) + (path_info[i].n)-1

  ; 获取点
  pts = path_xy[*,(path_info[i].offset):end_pos]

  ; 最后一个点必须与第一个点相同
  xs = [[pts[0,*]],[pts[0,0]]]
  ys = [[pts[1,*]],[pts[1,0]]]

  ; 创建ROI
  oROIs[i] = OBJ_NEW('IDLanROI', xs, ys)

  ; 计算掩膜
  Mask = oROIs[i]->ComputeMask(INITIALIZE=0, DIMENSIONS=[oRaster.ns,$
    oRaster.nl], Mask_Rule=2)

  ; 转换为二值图像
  Mask = Mask eq 255

  ; 将掩膜叠加到图像上
  overlap_img = overlap_img + Mask
endfor

图 3: 轮廓叠加图像

创建好叠加图像后,我搜索了满足 环比规则的区域。如果找到任何轮廓组,则记录下每个组的质心。

; 获取图像中的最大重叠次数
max_overlap = max(overlap_img)

; 设置期望的比例
desired_ratio1 = 2. + (2./3.)
desired_ratio2 = 1. + (7./9.)

; 为定位点创建容器
finder_cm = []

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

  ; 计算掩膜
  Mask = oROIs[i]->ComputeMask(INITIALIZE=0, DIMENSIONS=[oRaster.ns,$
    oRaster.nl], Mask_Rule=2)

  ; 转换为二值图像
  Mask = Mask eq 255

  ; 对叠加图像应用掩膜
  StudyArea = overlap_img * Mask

  ; 计算图像的直方图
  Hist = HISTOGRAM(StudyArea, LOCATIONS=pos, NBINS=nbins, BINSIZE = 1, MIN=1,$
    MAX=max_overlap)

  ; 如果数值不等于3个,则丢弃
  pos = where(Hist ne 0)
  if n_elements(pos) eq 3 then begin
    ; 获取每个区间的计数
    vals = float(hist[pos])

    ; 计算比例
    ; 外层黑环 / 内层黑块
    ratio1 =  vals[0] / vals[2]
    ; 白环 / 内层黑块
    ratio2 = vals[1] / vals[2]

    ; 检查比例与期望值的差异
    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.)

    ; 如果差异在30%以内,则保存为定位点
    if ratio1_dif_percent lt .3 and ratio2_dif_percent lt .3 then begin
      ; 计算质心
      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

      ; 记录质心
      finder_cm = [[finder_cm],[center_x,center_y]]

    endif
  endif
endfor

最后,但同样重要的是,我花了一点时间绘制结果并欣赏我的劳动成果。

; 显示输入图像
im = image(oRaster.GetData(interleave='bsq') )

; 在输入图像上绘制定位点的位置
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)

图 4: 最终结果

我希望你能从这个演示中学到一些东西。如果不是如何定位定位点,那么或许是如何以一种新颖而激动人心的方式使用轮廓分析。

一清二楚 用于规划传感器网络的通视分析