python裁剪图片边缘,使用Python自动裁剪图像以提取内部黑色边框ROI

I’ve been looking into OpenCV and Pillow (and ImageMagick outside of Python, especially Fred's Image Magick Scripts) to achieve the following:

Auto identification of an inner black border in scanned Images and cropping of the images to this said border. Here is a blacked out example Image, the first is the "original" and the second one with a red highlight around the black border is what I am looking to achieve:

f2bf0a80f9e6c93fed01ba5ca72989a9.png

3dd858624640a421cd4e51fd1f16772f.png

The problem is that the border is not on the outside of the images and the scans differ greatly in quality, meaning the border is never on the same spot and it’s not possible to crop by means of pixels.

Edit: I’m looking for a way to crop the image only keeping everything inside the black border (what is blurred right now)

I’m looking for help on how a) if it is possible to do such a cropping and b) how to do it preferably with Python.

Thanks!

解决方案

Here is a pretty simple way to do that in Imagemagick.

Get the center coordinates

Clone the image and do the following on the clone

Threshold the image so that the inside of the black lines is white.

(If necessary use -connected-components to merge smaller black features into the white in the center)

Apply some morphology open to make sure that the black lines are continuous

Floodfill the image with red starting in the center

Convert non-red to black and red to white

Put the processed clone into the alpha channel of the input

Input:

c97cbcb41d2bb45b5170d3017f39b443.png

center=$(convert img.jpg -format "%[fx:w/2],%[fx:h/2]\n" info:)

convert img.jpg \

\( +clone -auto-level -threshold 35% \

-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

3e6f56d8674c5f1c2687a0110161c366.png

Here is Python Wand code that is the equivalent to the above:

#!/bin/python3.7

from wand.image import Image

from wand.drawing import Drawing

from wand.color import Color

from wand.display import display

with Image(filename='black_rect.jpg') as img:

with img.clone() as copied:

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)

with Drawing() as draw:

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')

For OpenCV, I would suggest that the following processing could be one way to do it. Sorry, I am not proficient with OpenCV

Threshold the image so that the inside of the black lines is white.

Apply some morphology open to make sure that the black lines are continuous

Get the contours of the white regions.

Get the largest interior contour and fill the inside with white

Put that result into the alpha channel of the input

ADDITION:

For those interested, here is a longer method that would be conducive to perspective rectification. I do something similar to what nathancy has done, but in Imagemagick.

First, threshold the image and do morphology open to be sure the black lines are continuous.

Then do connected components to get the ID number of the largest white region

Then extract that region

id=$(convert img.jpg -auto-level -threshold 35% \

-morphology open disk:5 -type bilevel \

-define connected-components:mean-color=true \

-define connected-components:verbose=true \

-connected-components 8 null: | grep "gray(255)" | head -n 1 | awk '{print $1}' | sed 's/[:]*$//')

echo $id

convert img.jpg -auto-level -threshold 35% \

-morphology open disk:5 -type bilevel \

-define connected-components:mean-color=true \

-define connected-components:keep=$id \

-connected-components 8 \

-alpha extract -morphology erode disk:5 \

region.png

e56d2301396feef8f5ef18d15ec3bab1.png

Now do Canny edge detection and hough line transform. Here I save the canny image, the hough lines as red lines and the lines overlaid on the image and the line information, which is saved in the .mvg file.

convert region.png \

\( +clone -canny 0x1+10%+30% +write region_canny.png \

-background none -fill red -stroke red -strokewidth 2 \

-hough-lines 9x9+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+400

viewbox 0 0 2000 2829

# x1,y1 x2,y2 # count angle distance

line 0,202.862 2000,272.704 # 763 92 824

line 204.881,0 106.09,2829 # 990 2 1156

line 1783.84,0 1685.05,2829 # 450 2 2734

line 0,2620.34 2000,2690.18 # 604 92 3240

21706b29f0543d0e8819c9487129f3e1.png

276635493afcf9725a29563fc7b53c56.png

d93e49ad389739344ab16bc75078130e.png

6b27c4f97bb221a44bf5456d28229411.png

Next I use a script that I wrote to do corner detection. Here I use the Harris detector.

corners=$(corners -m harris -t 40 -d 5 -p yes region_bw_lines.png region_bw_lines_corners.png)

echo "$corners"

pt=1 coords=195.8,207.8

pt=2 coords=1772.8,262.8

pt=3 coords=111.5,2622.5

pt=4 coords=1688.5,2677.5

Next I extract and sort just the corners in clockwise fashion. The following is some code I wrote that I converted from here

list=$(echo "$corners" | sed -n 's/^.*=\(.*\)$/\1/p' | tr "\n" " " | sed 's/[ ]*$//' )

echo "$list"

195.8,207.8 1772.8,262.8 111.5,2622.5 1688.5,2677.5

# sort on x

xlist=`echo "$list" | tr " " "\n" | sort -n -t "," -k1,1`

leftmost=`echo "$xlist" | head -n 2`

rightmost=`echo "$xlist" | tail -n +3`

rightmost1=`echo "$rightmost" | head -n 1`

rightmost2=`echo "$rightmost" | tail -n +2`

# sort leftmost on y

leftmost2=`echo "$leftmost" | sort -n -t "," -k2,2`

topleft=`echo "$leftmost2" | head -n 1`

btmleft=`echo "$leftmost2" | tail -n +2`

# get distance from topleft to rightmost1 and rightmost2; largest is bottom right

topleftx=`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 -eq 1 ]; then

btmright=$rightmost1

topright=$rightmost2

else

btmright=$rightmost2

topright=$rightmost1

fi

sort_corners="$topleft $topright $btmright $btmleft"

echo $sort_corners

195.8,207.8 1772.8,262.8 1688.5,2677.5 111.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 -colorize 100 \

-fill white -draw "polygon $sort_corners" \) \

-alpha off -compose copy_opacity -composite result.png

74c30d13582a89296de7b0a663f77bf8.png

### 使用 Python 进行图像缩放 #### 利用 PIL 库进行图像缩放 对于图像的放大与缩小,`PIL`库提供了便捷的方法来调整图像大小。通过导入 `Image` 类可以轻松读取、修改以及保存图像文件。 ```python from PIL import Image def resize_image(input_path, output_path, size): with Image.open(input_path) as img: resized_img = img.resize(size, Image.ANTIALIAS) resized_img.save(output_path) resize_image('input.jpg', 'output_resized.jpg', (800, 600)) ``` 上述代码展示了如何定义一个函数 `resize_image()` 来改变指定路径下图片尺寸至给定的目标宽度和高度,并保持较好的质量[^1]。 #### 结合 NumPy 和 Matplotlib 实现更复杂的操作 除了基本的缩放功能外,有时还需要对图像执行更加精细的操作,这时就可以借助于 `NumPy` 数组运算能力和 `Matplotlib` 的绘图能力来进行复杂变换。 ```python import numpy as np import matplotlib.pyplot as plt from scipy.ndimage import zoom img_array = plt.imread('example.png') zoomed_img = zoom(img_array, (2, 2, 1)) # 放大两倍 plt.imshow(zoomed_img) plt.axis('off') # 不显示坐标轴 plt.show() ``` 这里展示了一个例子,其中使用了 `scipy.ndimage.zoom()` 函数来实现基于数组级别的图像放大效果[^2]。 #### 局部区域的选择性放大 当只需要关注某些特定部分时,则可以通过编程方式选取这些感兴趣区(ROI),并对它们单独应用放大算法后再拼接回原图中相应位置上形成最终结果。 ```python from PIL import Image, ImageDraw original_image = Image.open("source.jpg") roi_area_1 = (50, 50, 200, 200) # 定义第一个兴趣区的位置 cropped_region_1 = original_image.crop(roi_area_1).resize((400, 400), Image.ANTIALIAS) result_image = Image.new('RGB', (original_image.width * 2, max(original_image.height, cropped_region_1.height))) result_image.paste(original_image, (0, 0)) result_image.paste(cropped_region_1, (original_image.width, 0)) draw = ImageDraw.Draw(result_image) draw.rectangle([*roi_area_1], outline="red", width=3) result_image.save("final_result_with_highlighted_ROI_and_zoom_in.jpg") ``` 此段程序实现了从源图像裁剪出一个小范围的兴趣区并将其放大四倍后放置在新创建的结果图像右侧,同时还在原始位置周围绘制红色边框以便识别被选中的区域[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值