如何从JPEG裁剪多个矩形或正方形?

时间:2019-06-05 15:35:33

标签: python python-3.x image crop

我有一个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来达到此目的(猜测工作)。

裁剪前的图像: enter image description here

裁剪后的图像: enter image description here

基于某种逻辑,我对图像裁剪完全不是新手。在位置相同的情况下,如何成功裁剪所有图形以创建单独的图像?

更新:我相信,这不可能重复出现该问题,因为即使在逻辑上是相同的,但是集群逻辑的工作方式却有所不同。在这个问题中,只有2条垂直白线可以划分,但是这里有2条水平线和2条垂直线,我几乎不知道如何使用KMeans解决此类图像聚类。

非常感谢 sklearn的KMeans 专家提供的解决此类问题的帮助。

3 个答案:

答案 0 :(得分:3)

这是无需编写任何Python的第三种方法。它仅在终端中使用 ImageMagick -它已安装在大多数Linux发行版中,并且可用于macOS和Windows。

基本上,它使用与我其他答案相同的技术-阈值,中值过滤器和“连接组件分析” ,也称为“标签”

docker run --net=host -p 8000:8000 backend

示例输出

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

输出有一个标题行,告诉您这些字段是什么,然后在图像中找到的每个blob都有一行。让我们看一下这行:

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)

这意味着存在一个393像素宽,246像素高的blob,位于距左上角292,73处的偏移量,我们可以用半透明的蓝色对此进行绘制:

2: 393x246+292+73 488.0,195.5 96534 srgb(0,0,0)

enter image description here

我们可以这样做:

magick article.jpg -fill "rgba(0,0,255,0.5)" -draw "rectangle 292,73 685,319" result.png

enter image description here

第一个命令中带有标签的图像(magick article.jpg -crop 393x246+292+73 result.png )看起来像这样-您将看到每个斑点都被标记了不同的颜色(灰色阴影):

enter image description here


请注意,如果您的ImageMagick版本为v6或更高版本,则需要在所有上述命令中使用output.png而不是convert

答案 1 :(得分:2)

这是一种使用 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

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

中间的调试文件为result-1.png

enter image description here

还有result-2.png

enter image description here

答案 2 :(得分:2)

这是另一种方法,但是使用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

给出这些输出图像:

enter image description here

enter image description here

enter image description here

enter image description here

中间的调试映像为result-1.png

enter image description here

result-2.png

enter image description here