343

如何使用 OpenCV 裁剪图像,就像我之前在 PIL 中所做的那样。

PIL 的工作示例

im = Image.open('0.png').convert('L')
im = im.crop((1, 1, 98, 33))
im.save('_0.png')

但是我如何在 OpenCV 上做到这一点?

这是我尝试过的:

im = cv.imread('0.png', cv.CV_LOAD_IMAGE_GRAYSCALE)
(thresh, im_bw) = cv.threshold(im, 128, 255, cv.THRESH_OTSU)
im = cv.getRectSubPix(im_bw, (98, 33), (1, 1))
cv.imshow('Img', im)
cv.waitKey(0)

但它不起作用。

我想我错误地使用了getRectSubPix. 如果是这种情况,请解释我如何正确使用此功能。

4

12 回答 12

726

这很简单。使用 numpy 切片。

import cv2
img = cv2.imread("lenna.png")
crop_img = img[y:y+h, x:x+w]
cv2.imshow("cropped", crop_img)
cv2.waitKey(0)
于 2013-03-23T17:26:58.580 回答
153

我有这个问题,在这里找到了另一个答案:复制感兴趣的区域

如果我们将 (0,0) 视为图像im的左上角,则从左到右为 x 方向,从上到下为 y 方向。并且我们将 (x1,y1) 作为左上角顶点,将 (x2,y2) 作为该图像中矩形区域的右下角顶点,然后:

roi = im[y1:y2, x1:x2]

这是一个关于numpy 数组索引和切片的综合资源,它可以告诉你更多关于裁剪图像的一部分的信息。图像将作为一个 numpy 数组存储在 opencv2 中。

:)

于 2013-05-29T20:21:12.630 回答
32

此代码将图像从 x=0,y=0 裁剪到 h=100,w=200。

import numpy as np
import cv2

image = cv2.imread('download.jpg')
y=0
x=0
h=100
w=200
crop = image[y:y+h, x:x+w]
cv2.imshow('Image', crop)
cv2.waitKey(0) 
于 2018-12-31T09:44:39.730 回答
20

请注意,图像切片不是创建 的副本,而是cropped image创建. 如果您要加载这么多图像,用切片裁剪图像的相关部分,然后附加到列表中,这可能会浪费大量内存。pointerroi

假设您每个加载 N 个图像,>1MP并且您只需100x100要从左上角开始的区域。

Slicing

X = []
for i in range(N):
    im = imread('image_i')
    X.append(im[0:100,0:100]) # This will keep all N images in the memory. 
                              # Because they are still used.

或者,您可以通过 复制相关部分.copy(),因此垃圾收集器将删除im

X = []
for i in range(N):
    im = imread('image_i')
    X.append(im[0:100,0:100].copy()) # This will keep only the crops in the memory. 
                                     # im's will be deleted by gc.

发现这一点后,我意识到user1270710的评论之一提到了这一点,但我花了很长时间才发现(即调试等)。所以,我认为值得一提。

于 2018-11-27T10:03:13.810 回答
6

具有 opencv 复制边框功能的稳健裁剪:

def imcrop(img, bbox):
   x1, y1, x2, y2 = bbox
   if x1 < 0 or y1 < 0 or x2 > img.shape[1] or y2 > img.shape[0]:
        img, x1, x2, y1, y2 = pad_img_to_fit_bbox(img, x1, x2, y1, y2)
   return img[y1:y2, x1:x2, :]

def pad_img_to_fit_bbox(img, x1, x2, y1, y2):
    img = cv2.copyMakeBorder(img, - min(0, y1), max(y2 - img.shape[0], 0),
                            -min(0, x1), max(x2 - img.shape[1], 0),cv2.BORDER_REPLICATE)
   y2 += -min(0, y1)
   y1 += -min(0, y1)
   x2 += -min(0, x1)
   x1 += -min(0, x1)
   return img, x1, x2, y1, y2
于 2018-06-21T07:26:52.970 回答
6

下面是裁剪图像的方法。

image_path:要编辑的图像的路径

coords: x/y 坐标元组 (x1, y1, x2, y2)[在 mspaint 中打开图像并检查视图选项卡中的“标尺”以查看坐标]

saved_location:保存裁剪图像的路径

from PIL import Image
    def crop(image_path, coords, saved_location:
        image_obj = Image.open("Path of the image to be cropped")
            cropped_image = image_obj.crop(coords)
            cropped_image.save(saved_location)
            cropped_image.show()


if __name__ == '__main__':
    image = "image.jpg"
    crop(image, (100, 210, 710,380 ), 'cropped.jpg')
于 2019-04-17T05:29:43.427 回答
5

这是一些用于更强大的 imcrop 的代码(有点像 matlab 中的)

def imcrop(img, bbox): 
    x1,y1,x2,y2 = bbox
    if x1 < 0 or y1 < 0 or x2 > img.shape[1] or y2 > img.shape[0]:
        img, x1, x2, y1, y2 = pad_img_to_fit_bbox(img, x1, x2, y1, y2)
    return img[y1:y2, x1:x2, :]

def pad_img_to_fit_bbox(img, x1, x2, y1, y2):
    img = np.pad(img, ((np.abs(np.minimum(0, y1)), np.maximum(y2 - img.shape[0], 0)),
               (np.abs(np.minimum(0, x1)), np.maximum(x2 - img.shape[1], 0)), (0,0)), mode="constant")
    y1 += np.abs(np.minimum(0, y1))
    y2 += np.abs(np.minimum(0, y1))
    x1 += np.abs(np.minimum(0, x1))
    x2 += np.abs(np.minimum(0, x1))
    return img, x1, x2, y1, y2
于 2018-04-23T14:09:13.537 回答
1

或者,您可以使用 tensorflow 进行裁剪,使用 openCV 从图像制作数组。

import cv2
img = cv2.imread('YOURIMAGE.png')

现在img是一个 (imageheight, imagewidth, 3) 形状数组。使用 tensorflow 裁剪数组:

import tensorflow as tf
offset_height=0
offset_width=0
target_height=500
target_width=500
x = tf.image.crop_to_bounding_box(
    img, offset_height, offset_width, target_height, target_width
)

用 tf.keras 重新组装图像,这样我们就可以查看它是否有效:

tf.keras.preprocessing.image.array_to_img(
    x, data_format=None, scale=True, dtype=None
)

这会在笔记本中打印出图片(在 Google Colab 中测试)。


整个代码在一起:

import cv2
img = cv2.imread('YOURIMAGE.png')

import tensorflow as tf
offset_height=0
offset_width=0
target_height=500
target_width=500
x = tf.image.crop_to_bounding_box(
    img, offset_height, offset_width, target_height, target_width
)

tf.keras.preprocessing.image.array_to_img(
    x, data_format=None, scale=True, dtype=None
)
于 2020-03-31T11:02:00.920 回答
0

为了让您更轻松,这里是我使用的代码:

    top=514
    right=430
    height= 40
    width=100
    croped_image = image[top : (top + height) , right: (right + width)]
    plt.imshow(croped_image, cmap="gray")
    plt.show()
于 2020-11-12T19:48:11.523 回答
0

通过使用此功能,您可以轻松裁剪图像

def cropImage(Image, XY: tuple, WH: tuple, returnGrayscale=False):
    # Extract the x,y and w,h values
    (x, y) = XY
    (w, h) = WH
    # Crop Image with numpy splitting
    crop = Image[y:y + h, x:x + w]
    # Check if returnGrayscale Var is true if is then convert image to grayscale
    if returnGrayscale:
        crop = cv2.cvtColor(crop, cv2.COLOR_BGR2GRAY)
    # Return cropped image
    return crop

希望这可以帮助

于 2021-06-02T06:18:42.880 回答
0

在代码下方裁剪或感兴趣区域(ROI)以供面部使用

import cv2 
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
image=cv2.imread("ronaldo.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
     cv2.rectangle(img,(x,y),(x+w,y+h),(255,255,0),2) 
     roi_image = gray[y:y+h, x:x+w]
cv2.imshow("crop/region of interset image",roi_image) 
cv2.waitKey(0)
cv2.destroyAllWindows()

检查参考

于 2021-07-18T05:15:47.280 回答
0
# Import packages
import cv2

import numpy as np
img = cv2.imread('skewness.png')
print(img.shape) # Print image shape

cv2.imshow("original", img)

# Cropping an image
cropped_image = img[80:280, 150:330]
 
# Display cropped image
cv2.imshow("cropped", cropped_image)

# Save the cropped image
cv2.imwrite("Cropped Image.jpg", cropped_image)

#The function waitKey waits for a key event infinitely (when \f$\texttt{delay}\leq 0\f$ ) or for delay milliseconds, when it is positive
cv2.waitKey(0)

#The function destroyAllWindows destroys all of the opened HighGUI windows.
cv2.destroyAllWindows()
于 2021-12-07T14:38:18.937 回答