如何从 JPEG 裁剪多个矩形或正方形?
How to crop multiple rectangles or squares from JPEG?
我有一张 jpeg,我想从中裁剪包含图形的部分(底部的那个)。
截至目前,我使用此代码实现了相同的目的:
from PIL import Image
img = Image.open(r'D:\aakash\graph2.jpg')
area = (20, 320, 1040, 590)
img2 = img.crop(area)
# img.show()
img2.show()
但是我通过多次猜测 x1、y1、x2、y2 来达到这个目的(猜测工作)。
裁剪前的图片:
裁剪后的图片:
我在基于某种逻辑的图像裁剪方面完全是新手。如果位置相同,我如何才能成功裁剪所有图表以创建单独的图像?
更新: 我相信,这不可能是该问题的重复,因为尽管逻辑上相同,但集群逻辑的工作方式不同。那道题只有2条垂直的白线可以划分,而这里有两条横线和两条竖线,我几乎不知道如何使用KMeans来解决这种图像聚类问题。
非常感谢 sklearn 的 KMeans 专家帮助解决此类问题。
这是一种方法,使用 OpenCV findContours()
方法。
#!/usr/bin/env python3
import numpy as np
import cv2
# Load image
im = cv2.imread('article.jpg',cv2.IMREAD_UNCHANGED)
# Create greyscale version
gr = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# Threshold to get black and white
_,grthresh = cv2.threshold(gr,230,255,cv2.THRESH_BINARY)
cv2.imwrite('result-1.png',grthresh)
# Median filter to remove JPEG noise
grthresh = cv2.medianBlur(grthresh,11)
cv2.imwrite('result-2.png',grthresh)
# Find contours
im2, contours, hierarchy = cv2.findContours(grthresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
# Look through contours, checking what we found
blob = 0
for i in range(len(contours)):
area = cv2.contourArea(contours[i])
# Only consider ones taller than around 100 pixels and wider than about 300 pixels
if area > 30000:
# Get cropping box and crop
rc = cv2.minAreaRect(contours[i])
box = cv2.boxPoints(rc)
Xs = [ box[0,0], box[1,0], box[2,0], box[3,0]]
Ys = [ box[0,1], box[1,1], box[2,1], box[3,1]]
x0 = int(round(min(Xs)))
x1 = int(round(max(Xs)))
y0 = int(round(min(Ys)))
y1 = int(round(max(Ys)))
cv2.imwrite(f'blob-{blob}.png', im[y0:y1,x0:x1])
blob += 1
它给你这些文件:
-rw-r--r--@ 1 mark staff 248686 6 Jun 09:00 blob-0.png
-rw-r--r--@ 1 mark staff 92451 6 Jun 09:00 blob-1.png
-rw-r--r--@ 1 mark staff 101954 6 Jun 09:00 blob-2.png
-rw-r--r--@ 1 mark staff 102373 6 Jun 09:00 blob-3.png
-rw-r--r--@ 1 mark staff 633624 6 Jun 09:00 blob-4.png
中间调试文件是result-1.png
:
和result-2.png
:
这是另一种方法,但使用 PIL/Pillow 和 skimage
而不是 OpenCV:
#!/usr/local/bin/python3
import numpy as np
from PIL import Image, ImageFilter
from skimage.measure import label, regionprops
# Load image and make Numpy version and greyscale PIL version
pim = Image.open('article.jpg')
n = np.array(pim)
pgr = pim.convert('L')
# Threshold to make black and white
thr = pgr.point(lambda p: p < 230 and 255)
# Following line is just for debug
thr.save('result-1.png')
# Median filter to remove noise
fil = thr.filter(ImageFilter.MedianFilter(11))
# Following line is just for debug
fil.save('result-2.png')
# Make Numpy version for skimage to use
nim = np.array(fil)
# Image is now white blobs on black background, so label() it
label_image=label(nim)
# Iterate through blobs, saving each to disk
i=0
for region in regionprops(label_image):
if region.area >= 100:
# Extract rectangle containing blob and save
name="blob-" + str(i) + ".png"
minr, minc, maxr, maxc = region.bbox
Image.fromarray(n[minr:maxr,minc:maxc,:]).save(name)
i = i + 1
这给出了这些输出图像:
中间调试图像是 result-1.png
:
和result-2.png
:
这是无需编写任何内容的第三种方法 Python。它只在终端中使用 ImageMagick - 它安装在大多数 Linux 发行版上,可用于 macOS 和 Windows.
基本上,它使用与我的其他答案相同的技术——阈值、中值滤波器和"Connected Components Analysis"、a.k.a。 "labelling".
magick article.jpg -colorspace gray -threshold 95% -median 19x19 \
-define connected-components:verbose=true \
-define connected-components:area-threshold=100 \
-connected-components 4 -auto-level output.png
示例输出
Objects (id: bounding-box centroid area mean-color):
4: 963x241+38+333 519.0,453.0 231939 srgb(0,0,0)
0: 1045x590+0+0 528.0,204.0 155279 srgb(255,255,255)
2: 393x246+292+73 488.0,195.5 96534 srgb(0,0,0)
3: 303x246+698+73 849.0,195.5 74394 srgb(0,0,0)
1: 238x246+39+73 157.5,195.5 58404 srgb(0,0,0)
输出有一行 header 告诉您字段是什么,然后一行表示在图像中找到的每个 blob。让我们看看这一行:
2: 393x246+292+73 488.0,195.5 96534 srgb(0,0,0)
这意味着有一个 393 像素宽和 246 像素高的斑点,在距 top-left 角偏移 292,73 处,我们可以用 half-transparent 蓝色绘制:
magick article.jpg -fill "rgba(0,0,255,0.5)" -draw "rectangle 292,73 685,319" result.png
我们可以用这个裁剪出来:
magick article.jpg -crop 393x246+292+73 result.png
第一个命令中的标记图像 (output.png
) 如下所示 - 您会看到每个斑点都标记有不同的颜色(灰色阴影):
请注意,如果您的ImageMagick版本是v6或更早版本,您需要在上述所有命令中使用convert
而不是magick
。
我有一张 jpeg,我想从中裁剪包含图形的部分(底部的那个)。
截至目前,我使用此代码实现了相同的目的:
from PIL import Image
img = Image.open(r'D:\aakash\graph2.jpg')
area = (20, 320, 1040, 590)
img2 = img.crop(area)
# img.show()
img2.show()
但是我通过多次猜测 x1、y1、x2、y2 来达到这个目的(猜测工作)。
裁剪前的图片:
裁剪后的图片:
我在基于某种逻辑的图像裁剪方面完全是新手。如果位置相同,我如何才能成功裁剪所有图表以创建单独的图像?
更新: 我相信,这不可能是该问题的重复,因为尽管逻辑上相同,但集群逻辑的工作方式不同。那道题只有2条垂直的白线可以划分,而这里有两条横线和两条竖线,我几乎不知道如何使用KMeans来解决这种图像聚类问题。
非常感谢 sklearn 的 KMeans 专家帮助解决此类问题。
这是一种方法,使用 OpenCV findContours()
方法。
#!/usr/bin/env python3
import numpy as np
import cv2
# Load image
im = cv2.imread('article.jpg',cv2.IMREAD_UNCHANGED)
# Create greyscale version
gr = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# Threshold to get black and white
_,grthresh = cv2.threshold(gr,230,255,cv2.THRESH_BINARY)
cv2.imwrite('result-1.png',grthresh)
# Median filter to remove JPEG noise
grthresh = cv2.medianBlur(grthresh,11)
cv2.imwrite('result-2.png',grthresh)
# Find contours
im2, contours, hierarchy = cv2.findContours(grthresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
# Look through contours, checking what we found
blob = 0
for i in range(len(contours)):
area = cv2.contourArea(contours[i])
# Only consider ones taller than around 100 pixels and wider than about 300 pixels
if area > 30000:
# Get cropping box and crop
rc = cv2.minAreaRect(contours[i])
box = cv2.boxPoints(rc)
Xs = [ box[0,0], box[1,0], box[2,0], box[3,0]]
Ys = [ box[0,1], box[1,1], box[2,1], box[3,1]]
x0 = int(round(min(Xs)))
x1 = int(round(max(Xs)))
y0 = int(round(min(Ys)))
y1 = int(round(max(Ys)))
cv2.imwrite(f'blob-{blob}.png', im[y0:y1,x0:x1])
blob += 1
它给你这些文件:
-rw-r--r--@ 1 mark staff 248686 6 Jun 09:00 blob-0.png
-rw-r--r--@ 1 mark staff 92451 6 Jun 09:00 blob-1.png
-rw-r--r--@ 1 mark staff 101954 6 Jun 09:00 blob-2.png
-rw-r--r--@ 1 mark staff 102373 6 Jun 09:00 blob-3.png
-rw-r--r--@ 1 mark staff 633624 6 Jun 09:00 blob-4.png
中间调试文件是result-1.png
:
和result-2.png
:
这是另一种方法,但使用 PIL/Pillow 和 skimage
而不是 OpenCV:
#!/usr/local/bin/python3
import numpy as np
from PIL import Image, ImageFilter
from skimage.measure import label, regionprops
# Load image and make Numpy version and greyscale PIL version
pim = Image.open('article.jpg')
n = np.array(pim)
pgr = pim.convert('L')
# Threshold to make black and white
thr = pgr.point(lambda p: p < 230 and 255)
# Following line is just for debug
thr.save('result-1.png')
# Median filter to remove noise
fil = thr.filter(ImageFilter.MedianFilter(11))
# Following line is just for debug
fil.save('result-2.png')
# Make Numpy version for skimage to use
nim = np.array(fil)
# Image is now white blobs on black background, so label() it
label_image=label(nim)
# Iterate through blobs, saving each to disk
i=0
for region in regionprops(label_image):
if region.area >= 100:
# Extract rectangle containing blob and save
name="blob-" + str(i) + ".png"
minr, minc, maxr, maxc = region.bbox
Image.fromarray(n[minr:maxr,minc:maxc,:]).save(name)
i = i + 1
这给出了这些输出图像:
中间调试图像是 result-1.png
:
和result-2.png
:
这是无需编写任何内容的第三种方法 Python。它只在终端中使用 ImageMagick - 它安装在大多数 Linux 发行版上,可用于 macOS 和 Windows.
基本上,它使用与我的其他答案相同的技术——阈值、中值滤波器和"Connected Components Analysis"、a.k.a。 "labelling".
magick article.jpg -colorspace gray -threshold 95% -median 19x19 \
-define connected-components:verbose=true \
-define connected-components:area-threshold=100 \
-connected-components 4 -auto-level output.png
示例输出
Objects (id: bounding-box centroid area mean-color):
4: 963x241+38+333 519.0,453.0 231939 srgb(0,0,0)
0: 1045x590+0+0 528.0,204.0 155279 srgb(255,255,255)
2: 393x246+292+73 488.0,195.5 96534 srgb(0,0,0)
3: 303x246+698+73 849.0,195.5 74394 srgb(0,0,0)
1: 238x246+39+73 157.5,195.5 58404 srgb(0,0,0)
输出有一行 header 告诉您字段是什么,然后一行表示在图像中找到的每个 blob。让我们看看这一行:
2: 393x246+292+73 488.0,195.5 96534 srgb(0,0,0)
这意味着有一个 393 像素宽和 246 像素高的斑点,在距 top-left 角偏移 292,73 处,我们可以用 half-transparent 蓝色绘制:
magick article.jpg -fill "rgba(0,0,255,0.5)" -draw "rectangle 292,73 685,319" result.png
我们可以用这个裁剪出来:
magick article.jpg -crop 393x246+292+73 result.png
第一个命令中的标记图像 (output.png
) 如下所示 - 您会看到每个斑点都标记有不同的颜色(灰色阴影):
请注意,如果您的ImageMagick版本是v6或更早版本,您需要在上述所有命令中使用convert
而不是magick
。