如何在对扭曲或光线不敏感的情况下从照片中定位和提取迷宫

如何解决如何在对扭曲或光线不敏感的情况下从照片中定位和提取迷宫

我一直在问几个关于从 SOF 上的照片中定位和提取迷宫的问题, 但是我在不同的照片中得到的答案都没有,甚至在 4 张测试照片中也没有。 每次我调整代码以使其适用于 1 张照片时,由于扭曲的角落/部分或光线等,它会在其余照片上失败。我觉得我需要找到一种对扭曲图像不敏感且不同的方法光线强度或迷宫墙壁的不同颜色(迷宫内的线条)。

我一直在努力让它工作 3 周,但没有运气。在我放弃这个想法之前,我想问一下是否可以只使用没有 AI 的图像处理来从照片中定位和提取迷宫?如果是的话,你能告诉我怎么做吗?

这是代码和照片:

import cv2    
import numpy as np

from skimage.exposure import rescale_intensity
from skimage.feature import corner_harris,corner_subpix,corner_peaks
from skimage.io import imread,imshow
from skimage.morphology import reconstruction,binary_erosion,skeletonize,dilation,square
from skimage.morphology.convex_hull import convex_hull_image
from skimage.util import invert
from skmpe import parameters,mpe,OdeSolverMethod

maze=cv2.imread("simple.jpg",0)
ret,maze=cv2.threshold(maze,100,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
h,w = maze.shape
seed = np.zeros_like(maze)
size = 40
hh = h // 2
hw = w // 2
seed[hh-size:hh+size,hw-size:hw+size] = maze[hh-size:hh+size,hw-size:hw+size]
rec1 = reconstruction(seed,maze)
seed2 = np.ones_like(rec1)
ker = np.ones((2,2))
rec1_thicker = cv2.erode(rec1,ker,iterations=1)    

seed2 = seed2 * 255
size2 = 240
lhh = hh - size2
hhh = hh + size2
lhw = hw - size2
hhw = hw + size2
seed2[lhh:hhh,lhw:hhw]=rec1_thicker[lhh:hhh,lhw:hhw]
rec2 = reconstruction(seed2,rec1_thicker,method='erosion')
rec2_inv = invert(rec2 / 255.)
hull = convex_hull_image(rec2_inv)
hull_eroded = binary_erosion(hull,selem=np.ones((5,5)))
coords = corner_peaks(corner_harris(hull_eroded),min_distance=5,threshold_rel=0.02)

import matplotlib.pyplot as plt
fig,axe = plt.subplots(1,4,figsize=(16,8))
axe[0].imshow(maze,'gray')
axe[1].imshow(rec1,'gray')
axe[2].imshow(rec2,'gray')
axe[3].imshow(hull,'gray')

这是输出图像:

enter image description here

如您所见,第三个图是提取的迷宫,这段代码运行良好,但仅针对这 2 张照片,在本例中它们是 simple.jpg 和 'maze.jpg'...

如果你试过 `hard.jpg' 那么它看起来像这样:

enter image description here

它也在 middle.jpg 上失败:

enter image description here

我已将所有 4 张测试照片上传到 OneDrive,供任何有兴趣尝试的人使用。


更新 1

我绘制了所有面具以查看每个面具的作用。

mask = (sat < 16).astype(np.uint8) * 255
mask1 = cv2.morphologyEx(mask,cv2.MORPH_CLOSE,cv2.getStructuringElement(cv2.MORPH_RECT,(31,31)))
mask2 = cv2.copyMakeBorder(mask1,10,cv2.BORDER_CONSTANT,0)
mask3 = cv2.morphologyEx(mask2,cv2.MORPH_OPEN,(201,201)))

plt.figure(figsize=(18,8))
plt.subplot(1,6,1),plt.imshow(maze[...,::-1]),plt.title('White balanced image')
plt.subplot(1,2),plt.imshow(sat,'gray'),plt.title('Saturation channel')
plt.subplot(1,3),plt.imshow(mask,plt.title('sat < 16')
plt.subplot(1,4),plt.imshow(mask1,plt.title('closed')
plt.subplot(1,5),plt.imshow(mask2,plt.title('border')
plt.subplot(1,6),plt.imshow(mask3,plt.title('rect')
plt.tight_layout(),plt.show()

enter image description here

所以在我看来,在整个图像周围制作边框的 mask2 是没有必要的。 为什么我们需要 mask2?

我还发现mask2和mask3的分辨率在每个维度上都大了2个像素:

maze.shape,sat.shape,mask.shape,mask1.shape,mask2.shape,mask3.shape
((4000,1840,(4000,1840),(4002,1842),1842))

为什么?

解决方法

你真的想得到这些 6.9 美元的菜,他吗?


对于四个给定的图像,我可以使用以下工作流程获得相当不错的结果:

  • White balance 输入图像以强制执行接近白皮书。我使用图像中心的一个小块取 this approach,从那个块中,我取了具有最高 R + G + B 值的像素——假设迷宫总是在图像的中心,并且有小块内白纸上的一些像素。
  • 使用 HSV color space 中的饱和度通道遮盖白纸,并(粗略地)从图像中裁剪该部分。
  • 在该作物上,执行现有的 reconstruction 方法。

结果如下:

maze.jpg

Maze

simple.jpg

Simple

middle.jpg

Middle

hard.jpg

Hard

这是完整的代码:

import cv2
import matplotlib.pyplot as plt
import numpy as np
from skimage.morphology import binary_erosion,reconstruction
from skimage.morphology.convex_hull import convex_hull_image


# https://stackoverflow.com/a/54481969/11089932
def simple_white_balancing(image):
    h,w = image.shape[:2]
    patch = image[int(h/2-20):int(h/2+20),int(w/2-20):int(w/2+20)]
    x,y = cv2.minMaxLoc(np.sum(patch.astype(int),axis=2))[3]
    white_b,white_g,white_r = patch[y,x,...].astype(float)
    lum = (white_r + white_g + white_b) / 3
    image[...,0] = image[...,0] * lum / white_b
    image[...,1] = image[...,1] * lum / white_g
    image[...,2] = image[...,2] * lum / white_r
    return image


for file in ['maze.jpg','simple.jpg','middle.jpg','hard.jpg']:

    # Read image
    img = cv2.imread(file)

    # Initialize hull image
    h,w = img.shape[:2]
    hull = np.zeros((h,w),np.uint8)

    # Simple white balancing,cf. https://stackoverflow.com/a/54481969/11089932
    img = cv2.GaussianBlur(img,(11,11),None)
    maze = simple_white_balancing(img.copy())

    # Mask low saturation area
    sat = cv2.cvtColor(maze,cv2.COLOR_BGR2HSV)[...,1]
    mask = (sat < 16).astype(np.uint8) * 255
    mask = cv2.morphologyEx(mask,cv2.MORPH_CLOSE,cv2.getStructuringElement(cv2.MORPH_RECT,(31,31)))
    mask = cv2.copyMakeBorder(mask,1,cv2.BORDER_CONSTANT,0)
    mask = cv2.morphologyEx(mask,cv2.MORPH_OPEN,(201,201)))

    # Find largest contour in mask (w.r.t. the OpenCV version)
    cnts = cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    cnt = max(cnts,key=cv2.contourArea)
    x,y,w,h = cv2.boundingRect(cnt)

    # Crop to low saturation area
    cut = cv2.cvtColor(maze[y+1:y+1+h,x+1:x+1+w],cv2.COLOR_BGR2GRAY)

    # Use existing reconstruction approach on low saturation area
    h_c,w_c = cut.shape
    seed = np.zeros_like(cut)
    size = 40
    hh = h_c // 2
    hw = w_c // 2
    seed[hh-size:hh+size,hw-size:hw+size] = cut[hh-size:hh+size,hw-size:hw+size]
    rec = reconstruction(seed,cut)
    rec = cv2.erode(rec,np.ones((2,2)),iterations=1)

    seed = np.ones_like(rec) * 255
    size = 240
    seed[hh-size:hh+size,hw-size:hw+size] = rec[hh-size:hh+size,rec,method='erosion').astype(np.uint8)
    rec = cv2.threshold(rec,np.quantile(rec,0.25),255,cv2.THRESH_BINARY_INV)[1]

    hull[y+1:y+1+h,x+1:x+1+w] = convex_hull_image(rec) * 255

    plt.figure(figsize=(18,8))
    plt.subplot(1,5,1),plt.imshow(img[...,::-1]),plt.title('Original image')
    plt.subplot(1,2),plt.imshow(maze[...,plt.title('White balanced image')
    plt.subplot(1,3),plt.imshow(sat,'gray'),plt.title('Saturation channel')
    plt.subplot(1,4),plt.imshow(hull,plt.title('Obtained convex hull')
    plt.subplot(1,5),plt.imshow(cv2.bitwise_and(img,img,mask=hull)[...,::-1])
    plt.tight_layout(),plt.savefig(file + 'output.png'),plt.show()

当然,不能保证这种方法适用于接下来的五张左右的图像,您继续努力。一般来说,尝试标准化图像采集(旋转、照明)以获得更一致的图像。否则,您最终将需要一些机器学习方法...

----------------------------------------
System information
----------------------------------------
Platform:      Windows-10-10.0.16299-SP0
Python:        3.9.1
PyCharm:       2021.1.1
Matplotlib:    3.4.1
NumPy:         1.20.2
OpenCV:        4.5.1
scikit-image:  0.18.1
----------------------------------------

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res