我一直在研究OpenCV和Pillow(以及Python之外的ImageMagick,尤其是Fred的Image Magick脚本)以实现以下目的:
自动识别扫描图像中的内部黑色边框,并将图像裁剪到该边框。这是一个涂黑的示例图像,第一个是“原始图像”,第二个是在黑色边框周围带有红色突出显示的图像,这是我想要实现的目标:
问题在于,边框不在图像的外部,并且扫描的质量差异很大,这意味着边框永远不会位于同一位置,并且无法通过像素进行裁剪。
编辑:我正在寻找一种方法来裁剪图像,仅将所有内容保留在黑色边框内(现在模糊不清)
我正在寻求有关如何a)是否可以进行此类裁剪以及b)最好如何使用Python进行操作的帮助。
谢谢!
解决方案
这是在Imagemagick中执行此操作的一种非常简单的方法。
Getthe center coordinatesClonethe imageanddothe following on the cloneThresholdthe image so that the inside of the black linesiswhite.(Ifnecessary use-connected-components to merge smaller black features into the whiteinthe center)Applysome morphology open to make sure that the black lines are continuousFloodfillthe imagewithred startinginthe centerConvertnon-red to blackandred to whitePutthe processed clone into the alpha channel of the input
输入:
center=$(convert img.jpg-format"%[fx:w/2],%[fx:h/2]\n"info:)convert img.jpg \
\(+clone-auto-level-threshold35%\-morphology open disk:5\-fill red-draw"color $center floodfill"-alpha off \-fill black+opaque red-fill white-opaque red \) \-alpha off-compose copy_opacity-composite result.png
这是与以上等效的Python Wand代码:
#!/bin/python3.7fromwand.imageimportImagefromwand.drawingimportDrawingfromwand.colorimportColorfromwand.displayimportdisplaywithImage(filename='black_rect.jpg')asimg:withimg.clone()ascopied:copied.auto_level()copied.threshold(threshold=0.35)copied.morphology(method='open',kernel='disk:5')centx=round(0.5*copied.width)centy=round(0.5*copied.height)withDrawing()asdraw:draw.fill_color='red'draw.color(x=centx,y=centy,paint_method='floodfill')draw(copied)copied.opaque_paint(target='red',fill='black',fuzz=0.0,invert=True)copied.opaque_paint(target='red',fill='white',fuzz=0.0,invert=False)display(copied)copied.alpha_channel='copy'img.composite(copied,left=0,top=0,operator='copy_alpha')img.format='png'display(img)img.save(filename='black_rect_interior.png')
对于OpenCV,我建议进行以下处理是一种方法。抱歉,我不精通OpenCV
Thresholdthe image so that the inside of the black linesiswhite.Applysome morphology open to make sure that the black lines are continuousGetthe contours of the white regions.Getthe largest interior contourandfill the insidewithwhitePutthat result into the alpha channel of the input
加成:
对于那些感兴趣的人,这是一种更长的方法,将有利于透视矫正。我做的事情与nathancy相似,但在Imagemagick中。
首先,对图像进行阈值处理并打开形态以确保黑线是连续的。
然后进行连接的组件以获取最大的白色区域的ID号
然后提取该区域
id=$(convert img.jpg-auto-level-threshold35%\-morphology open disk:5-type bilevel \-define connected-components:mean-color=true \-define connected-components:verbose=true \-connected-components8null:|grep"gray(255)"|head-n1|awk'{print $1}'|sed's/[:]*$//')echo $id
convert img.jpg-auto-level-threshold35%\-morphology open disk:5-type bilevel \-define connected-components:mean-color=true \-define connected-components:keep=$id \-connected-components8\-alpha extract-morphology erode disk:5\
region.png
现在进行Canny边缘检测和霍夫线变换。在这里,我将canny图像,hough线保存为红色线条,并将图像上的线条和线条信息保存在.mvg文件中。
convert region.png \
\(+clone-canny0x1+10%+30%+write region_canny.png \-background none-fill red-stroke red-strokewidth2\-hough-lines9x9+400+write region_lines.png+write lines.mvg \) \-compose over-composite region_hough.png
convert region_lines.png-alpha extract region_bw_lines.png# Hough line transform: 9x9+400viewbox0020002829# x1,y1 x2,y2 # count angle distanceline0,202.8622000,272.704# 763 92 824line204.881,0106.09,2829# 990 2 1156line1783.84,01685.05,2829# 450 2 2734line0,2620.342000,2690.18# 604 92 3240
接下来,我使用编写的脚本进行角点检测。在这里,我使用哈里斯探测器。
corners=$(corners-m harris-t40-d5-p yes region_bw_lines.png region_bw_lines_corners.png)echo"$corners"pt=1coords=195.8,207.8pt=2coords=1772.8,262.8pt=3coords=111.5,2622.5pt=4coords=1688.5,2677.5
接下来,我按顺时针方式提取并仅对角进行排序。以下是我写的从这里转换的一些代码
list=$(echo"$corners"|sed-n's/^.*=\(.*\)$/\1/p'|tr"\n"" "|sed's/[ ]*$//')echo"$list"195.8,207.81772.8,262.8111.5,2622.51688.5,2677.5# sort on xxlist=`echo"$list"|tr" ""\n"|sort-n-t","-k1,1`leftmost=`echo"$xlist"|head-n2`rightmost=`echo"$xlist"|tail-n+3`rightmost1=`echo"$rightmost"|head-n1`rightmost2=`echo"$rightmost"|tail-n+2`# sort leftmost on yleftmost2=`echo"$leftmost"|sort-n-t","-k2,2`topleft=`echo"$leftmost2"|head-n1`btmleft=`echo"$leftmost2"|tail-n+2`# get distance from topleft to rightmost1 and rightmost2; largest is bottom righttopleftx=`echo"$topleft"|cut-d,-f1`toplefty=`echo"$topleft"|cut-d,-f2`rightmost1x=`echo"$rightmost1"|cut-d,-f1`rightmost1y=`echo"$rightmost1"|cut-d,-f2`rightmost2x=`echo"$rightmost2"|cut-d,-f1`rightmost2y=`echo"$rightmost2"|cut-d,-f2`dist1=`convert xc:-format"%[fx:hypot(($topleftx-$rightmost1x),($toplefty-$rightmost1y))]"info:`dist2=`convert xc:-format"%[fx:hypot(($topleftx-$rightmost2x),($toplefty-$rightmost2y))]"info:`test=`convert xc:-format"%[fx:$dist1>$dist2?1:0]"info:`if[$test-eq1];then
btmright=$rightmost1
topright=$rightmost2elsebtmright=$rightmost2
topright=$rightmost1
fi
sort_corners="$topleft $topright $btmright $btmleft"echo $sort_corners195.8,207.81772.8,262.81688.5,2677.5111.5,2622.5
Finally, I use the corner coordinates to draw a white filled polygon on a black background and put that result into the alpha channel of the input image.
convert img.jpg \
\(+clone-fill black-colorize100\-fill white-draw"polygon $sort_corners"\) \-alpha off-compose copy_opacity-composite result.png