I have some problem with preprocessing of an image. I have this picture of a book on my desk:
I'm trying to get the shape of the book (a filled rectangle) in black&white using cv2 adaptive threshold
ts_img = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,11,2)
but what I get is just the edges of figure with a lot of noise, for example the edges of the title. Is there a way to get just the black filled rectangle that represents the book on white background? Thanks!
Since the book is blue, just search for the pixels where the blue channel is higher than r, you can make this also more robust by specifying factors and so on.
Here is my approach:
import cv2
%matplotlib notebook
import matplotlib.pyplot as plt
import numpy as np
imRGB = cv2.cvtColor(cv2.imread("book.jpg"), cv2.COLOR_BGR2RGB) # read and convert to RGB for easier plotting
r,g,b = cv2.split(imRGB) # split into different channels
mask = (b>r).astype(np.uint8) # where blue channel is higher
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # find contours
largestContour = max(contours, key = cv2.contourArea) # get the largest contour by area
imContoured = cv2.drawContours(imRGB.copy(), largestContour, -1, (255,0,0), 10) # draw contour
cv2.imwrite("contoured.jpg", cv2.cvtColor(imContoured, cv2.COLOR_RGB2BGR)) # save image
And the results:
As fmw42 mentioned, the best answers are the simplest. cv2.adaptiveThreshold
is not an easy function to use and in this case, the obvious approach should be to go with colour channels instead of dynamic thresholds