How to crop an image in OpenCV using Python

PythonOpencv

Python Problem Overview


How can I crop images, like I've done before in PIL, using OpenCV.

Working example on PIL

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

But how I can do it on OpenCV?

This is what I tried:

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)

But it doesn't work.

I think I incorrectly used getRectSubPix. If this is the case, please explain how I can correctly use this function.

Python Solutions


Solution 1 - Python

It's very simple. Use numpy slicing.

import cv2
img = cv2.imread("lenna.png")
crop_img = img[y:y+h, x:x+w]
cv2.imshow("cropped", crop_img)
cv2.waitKey(0)

Solution 2 - Python

i had this question and found another answer here: copy region of interest

If we consider (0,0) as top left corner of image called im with left-to-right as x direction and top-to-bottom as y direction. and we have (x1,y1) as the top-left vertex and (x2,y2) as the bottom-right vertex of a rectangle region within that image, then:

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

here is a comprehensive resource on numpy array indexing and slicing which can tell you more about things like cropping a part of an image. images would be stored as a numpy array in opencv2.

:)

Solution 3 - Python

This code crops an image from x=0,y=0 to 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) 

Solution 4 - Python

Note that, image slicing is not creating a copy of the cropped image but creating a pointer to the roi. If you are loading so many images, cropping the relevant parts of the images with slicing, then appending into a list, this might be a huge memory waste.

Suppose you load N images each is >1MP and you need only 100x100 region from the upper left corner.

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.

Alternatively, you can copy the relevant part by .copy(), so garbage collector will remove 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.

After finding out this, I realized one of the comments by user1270710 mentioned that but it took me quite some time to find out (i.e., debugging etc). So, I think it worths mentioning.

Solution 5 - Python

Robust crop with opencv copy border function:

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

Solution 6 - Python

Below is the way to crop an image.

image_path: The path to the image to edit

coords: A tuple of x/y coordinates (x1, y1, x2, y2)[open the image in mspaint and check the "ruler" in view tab to see the coordinates]

saved_location: Path to save the cropped image

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

Solution 7 - Python

here is some code for more robust imcrop ( a bit like in 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

Solution 8 - Python

Alternatively, you could use tensorflow for the cropping and openCV for making an array from the image.

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

Now img is a (imageheight, imagewidth, 3) shape array. Crop the array with 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
)

Reassemble the image with tf.keras, so we can look at it if it worked:

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

This prints out the pic in a notebook (tested in Google Colab).


The whole code together:

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
)

Solution 9 - Python

to make it easier for you here is the code that i use :

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

Solution 10 - Python

By using this function you can easily crop image

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

HOPE THIS HELPS

Solution 11 - Python

to crop or region of interest(ROI) for face use below code

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

check for reference

Solution 12 - Python

# 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()

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNolikView Question on Stackoverflow
Solution 1 - PythonFroyoView Answer on Stackoverflow
Solution 2 - Pythonsamkhan13View Answer on Stackoverflow
Solution 3 - Pythonm.hatamiView Answer on Stackoverflow
Solution 4 - PythonsmttspView Answer on Stackoverflow
Solution 5 - PythonbelgravitonView Answer on Stackoverflow
Solution 6 - PythonSanyalView Answer on Stackoverflow
Solution 7 - PythonDan ErezView Answer on Stackoverflow
Solution 8 - PythonzabopView Answer on Stackoverflow
Solution 9 - PythonEl Houcine Es-sanhajiView Answer on Stackoverflow
Solution 10 - PythonPrathamesh Bhatkar21View Answer on Stackoverflow
Solution 11 - PythonBharat NatraynView Answer on Stackoverflow
Solution 12 - PythonAdesoji AluView Answer on Stackoverflow