├── shadow1.jpg ├── shadow2.jpg ├── shadow3.jpg ├── Shadow Detection and Removal Based on YCbCr Color Space.pdf ├── .idea └── vcs.xml └── shadow-removal-based-on-YCbCr-color-space.py /shadow1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmostipan/shadow-removal/HEAD/shadow1.jpg -------------------------------------------------------------------------------- /shadow2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmostipan/shadow-removal/HEAD/shadow2.jpg -------------------------------------------------------------------------------- /shadow3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmostipan/shadow-removal/HEAD/shadow3.jpg -------------------------------------------------------------------------------- /Shadow Detection and Removal Based on YCbCr Color Space.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmostipan/shadow-removal/HEAD/Shadow Detection and Removal Based on YCbCr Color Space.pdf -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /shadow-removal-based-on-YCbCr-color-space.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | 4 | # read an image with shadow... 5 | # and it converts to BGR color space automatically 6 | or_img = cv2.imread('shadow4.jpg') 7 | 8 | # covert the BGR image to an YCbCr image 9 | y_cb_cr_img = cv2.cvtColor(or_img, cv2.COLOR_BGR2YCrCb) 10 | 11 | # copy the image to create a binary mask later 12 | binary_mask = np.copy(y_cb_cr_img) 13 | 14 | # get mean value of the pixels in Y plane 15 | y_mean = np.mean(cv2.split(y_cb_cr_img)[0]) 16 | 17 | # get standard deviation of channel in Y plane 18 | y_std = np.std(cv2.split(y_cb_cr_img)[0]) 19 | 20 | # classify pixels as shadow and non-shadow pixels 21 | for i in range(y_cb_cr_img.shape[0]): 22 | for j in range(y_cb_cr_img.shape[1]): 23 | 24 | if y_cb_cr_img[i, j, 0] < y_mean - (y_std / 3): 25 | # paint it white (shadow) 26 | binary_mask[i, j] = [255, 255, 255] 27 | else: 28 | # paint it black (non-shadow) 29 | binary_mask[i, j] = [0, 0, 0] 30 | 31 | # Using morphological operation 32 | # The misclassified pixels are 33 | # removed using dilation followed by erosion. 34 | kernel = np.ones((3, 3), np.uint8) 35 | erosion = cv2.erode(binary_mask, kernel, iterations=1) 36 | 37 | # sum of pixel intensities in the lit areas 38 | spi_la = 0 39 | 40 | # sum of pixel intensities in the shadow 41 | spi_s = 0 42 | 43 | # number of pixels in the lit areas 44 | n_la = 0 45 | 46 | # number of pixels in the shadow 47 | n_s = 0 48 | 49 | # get sum of pixel intensities in the lit areas 50 | # and sum of pixel intensities in the shadow 51 | for i in range(y_cb_cr_img.shape[0]): 52 | for j in range(y_cb_cr_img.shape[1]): 53 | if erosion[i, j, 0] == 0 and erosion[i, j, 1] == 0 and erosion[i, j, 2] == 0: 54 | spi_la = spi_la + y_cb_cr_img[i, j, 0] 55 | n_la += 1 56 | else: 57 | spi_s = spi_s + y_cb_cr_img[i, j, 0] 58 | n_s += 1 59 | 60 | # get the average pixel intensities in the lit areas 61 | average_ld = spi_la / n_la 62 | 63 | # get the average pixel intensities in the shadow 64 | average_le = spi_s / n_s 65 | 66 | # difference of the pixel intensities in the shadow and lit areas 67 | i_diff = average_ld - average_le 68 | 69 | # get the ratio between average shadow pixels and average lit pixels 70 | ratio_as_al = average_ld / average_le 71 | 72 | # added these difference 73 | for i in range(y_cb_cr_img.shape[0]): 74 | for j in range(y_cb_cr_img.shape[1]): 75 | if erosion[i, j, 0] == 255 and erosion[i, j, 1] == 255 and erosion[i, j, 2] == 255: 76 | 77 | y_cb_cr_img[i, j] = [y_cb_cr_img[i, j, 0] + i_diff, y_cb_cr_img[i, j, 1] + ratio_as_al, 78 | y_cb_cr_img[i, j, 2] + ratio_as_al] 79 | 80 | # covert the YCbCr image to the BGR image 81 | final_image = cv2.cvtColor(y_cb_cr_img, cv2.COLOR_YCR_CB2BGR) 82 | 83 | cv2.imshow("im1", or_img) 84 | cv2.imshow("im2", final_image) 85 | cv2.waitKey(0) 86 | cv2.destroyAllWindows() 87 | --------------------------------------------------------------------------------