I m working to create a CBIR, I want to use Zernike moment to get shape feature of a query image.
I try to implement it by following this tutoriel: https://pyimagesearch.com/2014/05/19/building-pokedex-python-comparing-shape-descriptors-opencv/
But actually it doesn't work.
After some hours a investigating, I found that outline image doesn't get (or barely) get shape; instead, I get all of the image as a the shape. So all of the image gives me a big square as the shape.
Screenshots here :
Here is my code:
from statistics import mode
from turtle import width
from scipy.spatial import distance, distance_matrix #pip install scipy
import matplotlib.pyplot as plt
from skimage.feature import hog #pip3 install scikit-image matplotlib
from skimage import data, exposure
from cv2 import waitKey
import mahotas #pip install mahotas
import cv2
import matplotlib.pyplot as plt
import numpy as np
import imutils #pip install imutils.#
#Search Shape
def SearchShape(raduis, image):
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# pad the image with extra white pixels to ensure the
# edges of the earplane are not up against the borders
# of the image
image = cv2.copyMakeBorder(image, 15, 15, 15, 15, cv2.BORDER_CONSTANT, value = 255)
# invert the image and threshold it
thresh = cv2.bitwise_not(image)
thresh[thresh > 0] = 255
# initialize the outline image, find the outermost
# contours (the outline) of the earplane, then draw
outline = np.zeros(image.shape, dtype = "uint8")
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[0]
cv2.drawContours(outline, [cnts], -1, 255, -1)
# compute Zernike moments to characterize the shape
# of earplane outline, then update the index
momentsArray = mahotas.features.zernike_moments(thresh, raduis) #outline, raduis)
#Convert : array([....]) to [...]
moments = []
for m in momentsArray:
moments.append(m)
cv2.imshow("", image)
cv2.waitKey(0)
cv2.imshow("", thresh)
cv2.waitKey(0)
cv2.imshow("", outline)
cv2.waitKey(0)
#print("MOMENT Liste IS: ", moments)
return moments
#Shape descriptor
#tres proche#
queryFeatures = SearchShape(21, cv2.imread("./JPEGImages/2007_000033.jpg"))
features = SearchShape(21, cv2.imread("./JPEGImages/2007_000738.jpg"))
d = distance.euclidean(queryFeatures, features)
print("distance is: ", d)
Edited: After more test, i found that some value given to cnts (which i suppose should help to draw shape) are pretty close to image shape (here a value in cnts). May be there is some probleme with cv2.findContours or cv2.bitwise_not, or imutils.grab_contours or cv2.drawContours
but thresh look good because if i change the value thresh[thresh > 0] = 255 to thresh[thresh > 100] = 255 ; cv.imshow show some shape in thresh
I finally, i get the answer. i just changed the thresh[thresh > 0] = 255 to thresh[thresh > 15] = 255 and reverse the color just after. the solved code is here:
I get the shape of some object, this method don t get needed shape for all images. the precision given to pretty low on my cbir system.
Image of result: Gray image
Threash image
Outline image