Search code examples
pythonopencvrgbcrop

to crop the rgb image based on the pixel value


I am having an rgb image and I want to crop it from all sides. i have tried the below code on gray scale image it works but for RGB image it doesn't. My code is:

    import cv2 
    import numpy as np
    import glob,os
    from PIL import Image
    
    inputdir = "/Users/sripdeep/Desktop/Projects/3 Norm_Sub_Norm/rgb/"
    outpath = "/Users/sripdeep/Desktop/Projects/3 Norm_Sub_Norm/rgb_norm/"
    
    #filesname = sorted(glob.glob( inputdir + "*.jpg"))
    
    for img1 in sorted(glob.glob( inputdir + "*.jpeg")):
        
        img_path = img1.split('/')[-1]
        imgstr = img_path.split('.')[0]
        
        print(imgstr)
        im1 = cv2.imread(img1,0)
        thresh = cv2.threshold(im1, 100, 255, cv2.THRESH_BINARY)[1]
        x, y, w, h = cv2.boundingRect(im1)           #  calculates nonzero pixels 
#        print(x,y,w,h)
#        a tuple (x, y, w, h) with (x, y) the upper left point 
#        as well as width w and height h of the bounding rectangle.

        left = (x, np.argmax(thresh[:, x]))             # 
        right = (x+w-1, np.argmax(thresh[:, x+w-1]))    # 
        top = (np.argmax(thresh[y, :]), y)              # 
        bottom = (np.argmax(thresh[y+h-1, :]), y+h-1) 
        
        print('left: {}'.format(left))
        print('right: {}'.format(right))
        print('top: {}'.format(top))
        print('bottom: {}'.format(bottom))
        
#        cropped__img = img[y1:y2, x1:x2]
        cropped__img = thresh[top[1]:bottom[1], left[0]:right[0]]
        cropped__img = cv2.resize(cropped__img, (256,256), interpolation=cv2.INTER_LINEAR)
        
        save_fname = os.path.join(outpath, os.path.basename(imgstr)+'.jpg')
        cv2.imwrite(save_fname, cropped__img)

I want my image to be cropped like this:

enter image description here

But I get output is:

enter image description here


Solution

  • Your approach is close, and can be simplified a bit.

    Note that cv2.boundingRect(..) can only be applied on single channel images. Because of this, it seems easiest to first read a color image, then convert it to grayscale to figure out bounding rectangle (x,h,w,h) coordinates (x1, y1, x2, y2), and then apply cropping to the original color image. Perhaps something like this:

    im1 = cv2.imread(img1,0) # color image
    im1_gray = cv2.cvtColor(im1, cv2.COLOR_BGR2GRAY) # grayscale
    thresh = cv2.threshold(im1_gray, 100, 255, cv2.THRESH_BINARY)[1] # threshold image
    x, y, w, h = cv2.boundingRect(thresh) # find the bounding rectangle of nonzero points in the image
    cropped__img = im1[y:y+h, x:x+w,:] # crop the original color image