import cv2 as cv import numpy as np import matplotlib.pyplot as plt from matplotlib import colors, cm from mpl_toolkits.mplot3d import Axes3D from scipy.interpolate import splprep, splev pixel_thresold_pct = 0.05 def get_img_histogram(img, colors, gray): """Saves color channel masked images to numbered jpg images.""" img_n = 0 for color in colors[0]: split_img = img.copy() split_img[np.where(gray != color)] = 0 cv.imwrite(str(img_n) + ".jpg", split_img) img_n += 1 plt.hist(gray.ravel(), 256, [0,256]) plt.savefig('histogram.jpg') plt.show() def smooth_contours(contours, img): smoooth = [] for contour in contours: x, y = contour.T x = x.tolist()[0] y = y.tolist()[0] tck, u = splprep([x, y], u=None, k=1, s=1.0, per=1) u_new = np.linspace(u.min(), u.max(), 25) x_new, y_new = splev(u_new, tck, der=0) res_array = [[[int(i[0]), int(i[1])]] for i in zip(x_new, y_new)] smoooth.append(np.asarray(res_array, dtype=np.int32)) cv2.drawContours(img, smoooth, -1, (255,255,255), 2) copy = img.copy() cv.imwrite('contour_smooth.jpg', copy) def color_range_mask(hsv, color_start, color_end, name): mask = cv.inRange(hsv, color_start, color_end) result = cv.bitwise_and(img, img, mask=mask) result[mask == 255] = (255, 255, 255) cv.imwrite(f'{name}.png', result) return result def get_pixel_representations(img): # Get color representations from rgb rgb = cv.cvtColor(img, cv.COLOR_BGR2RGB) pixel_colors = rgb.reshape((np.shape(rgb)[0] * np.shape(rgb)[1], 3)) norm = colors.Normalize(vmin=-1., vmax=1.) norm.autoscale(pixel_colors) pixel_colors = norm(pixel_colors).tolist() return pixel_colors def threshold_and_contour(image, name): gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(gray, 150, 255, cv.THRESH_BINARY) cv.imwrite(f'thresholded_{name}.png', thresh) contours, _ = cv.findContours(image=thresh, mode=cv.RETR_TREE, method=cv.CHAIN_APPROX_NONE) # Smooth contours copy = img.copy() cv.drawContours(image=copy, contours=contours, contourIdx=-1, color=(0, 255, 0), thickness=2, lineType=cv.LINE_AA) cv.imwrite(f'contoured_{name}.png', copy) def get_hsv_plot(img, pixel_colors): # Get HSV color representation hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV) h, s, v = cv.split(hsv) h_flat = h.flatten() s_flat = s.flatten() v_flat = v.flatten() fig = plt.figure() axis = fig.add_subplot(1, 1, 1, projection="3d") max_value = np.max(v_flat) # Filter for coords TODO: make this better coords = [] for idx, value in enumerate(v_flat): if value >= 0.99 * max_value: coords.append((h_flat[idx], s_flat[idx], value)) coords = list(set(coords)) axis.scatter(h_flat, s_flat, v_flat, facecolors=pixel_colors, marker=".") axis.set_xlabel("Hue") axis.set_ylabel("Saturation") axis.set_zlabel("Value") plt.savefig('hsv_spectrum.jpg') plt.close() return hsv if __name__ == '__main__': # Blur and resize original image img = cv.imread("cowboy_bebop_test.jpg") blur = cv.blur(img,(4, 4)) blur0=cv.medianBlur(blur,5) blur1 = cv.GaussianBlur(blur, (5,5),0) cv.imwrite('blur.jpg', blur1) pixel_colors = get_pixel_representations(img) hsv = get_hsv_plot(blur1, pixel_colors) # Two manually selected colors based on hsv plot color_start_o = (0, 60, 100) color_end_o = (70, 305, 255) color_start_b = (0, 0, 0) color_end_b = (300, 300, 50) mask1 = color_range_mask(hsv, color_start_o, color_end_o, 'mask1') mask2 = color_range_mask(hsv, color_start_b, color_end_b, 'mask2') threshold_and_contour(mask1, 'color_mask1') threshold_and_contour(mask2, 'color_mask2')