【问题标题】:How to crop multiple rectangles or squares from JPEG?如何从 JPEG 中裁剪多个矩形或正方形?
【发布时间】:2019-10-21 03:42:09
【问题描述】:

我有一个 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 来实现这一点(猜测工作)。

裁剪前的图像:

裁剪后的图像:

我在基于某些逻辑的图像裁剪方面完全是新手。鉴于位置相同,如何成功裁剪所有图表以创建单独的图像?

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

sklearn 的 KMeans 专家帮助解决此类问题将不胜感激。

【问题讨论】:

  • img 变量中仍有整张图像,您可以裁剪另一部分并将其保存在新变量中。
  • 我知道,但我想要一种有效的方法来检测位置,以便可以自动完成裁剪。到目前为止,我所做的完全是手动的(多次猜测)。我在理解图像分割或一些分离像素颜色的算法等方面非常差。所以,希望从 SO 社区获得一些解决方案。
  • 虽然逻辑上是一样的,但是集群逻辑的工作方式是不同的。在那个问题中,只有两条垂直的白线要划分,但这里有两条水平线和两条垂直线,我几乎不知道如何使用 KMeans 来解决这种图像聚类。请问您能帮忙解决这种问题吗?

标签: python python-3.x image crop


【解决方案1】:

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

【讨论】:

    【解决方案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
    

    这给出了这些输出图像:

    中间的调试图像是result-1.png

    result-2.png:

    【讨论】:

    • 嘿,马克,令人惊叹的作品。您认为三个答案中哪一个更有效(在时间和计算能力方面)并且可以适用于不同的解决方案?如,来自其他页面的图表(我在问题中给出的文档链接)。
    • 我不知道——这取决于你的文档、你的操作系统、你自己的灵巧度、你的磁盘性能和各种各样的事情。我已经给了你所有的代码,所以尝试一些看看 - 尽职尽责地支持你喜欢的任何人!如果您有很多文档要做,您可能想看看我的其他几个答案,它们使用 GNUI Parallel 来快速处理数千张图像 stackoverflow.com/a/56279321/2836621stackoverflow.com/a/56472590/2836621
    【解决方案3】:

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

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

    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)
    

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

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

    这意味着有一个 393 px 宽和 246 px 高的斑点,从左上角偏移 292,73,我们可以用这个半透明的蓝色绘制:

    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) 如下所示 - 您会看到每个 blob 都标有不同的颜色(灰色阴影):


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

    【讨论】:

    • 一个非常幼稚的问题,这个解决方案中的任何人都可以通过 PDF 运行并拾取在某些框/矩形/圆圈中着色的所有图形或对象吗?我知道这是一个非常广泛(无限)的问题,但如果你能帮助回答这个问题会很好。
    • @AakashBasu 尝试使用 Poppler 工具套件中的 pdfimages 命令行工具,看看你的表现如何。
    猜你喜欢
    • 2020-08-27
    • 1970-01-01
    • 2011-09-08
    • 1970-01-01
    • 2013-02-16
    • 2013-10-05
    • 1970-01-01
    • 2014-02-03
    相关资源
    最近更新 更多