├── sd.jpg ├── MSR.jpg ├── SSR.jpg ├── retinex.py └── README.md /sd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AKRISH22/Retinex-Image-Enhancement/HEAD/sd.jpg -------------------------------------------------------------------------------- /MSR.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AKRISH22/Retinex-Image-Enhancement/HEAD/MSR.jpg -------------------------------------------------------------------------------- /SSR.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AKRISH22/Retinex-Image-Enhancement/HEAD/SSR.jpg -------------------------------------------------------------------------------- /retinex.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | 4 | def singleScaleRetinex(img,variance): 5 | retinex = np.log10(img) - np.log10(cv2.GaussianBlur(img, (0, 0), variance)) 6 | return retinex 7 | 8 | def multiScaleRetinex(img, variance_list): 9 | retinex = np.zeros_like(img) 10 | for variance in variance_list: 11 | retinex += singleScaleRetinex(img, variance) 12 | retinex = retinex / len(variance_list) 13 | return retinex 14 | 15 | 16 | 17 | def MSR(img, variance_list): 18 | img = np.float64(img) + 1.0 19 | img_retinex = multiScaleRetinex(img, variance_list) 20 | 21 | for i in range(img_retinex.shape[2]): 22 | unique, count = np.unique(np.int32(img_retinex[:, :, i] * 100), return_counts=True) 23 | for u, c in zip(unique, count): 24 | if u == 0: 25 | zero_count = c 26 | break 27 | low_val = unique[0] / 100.0 28 | high_val = unique[-1] / 100.0 29 | for u, c in zip(unique, count): 30 | if u < 0 and c < zero_count * 0.1: 31 | low_val = u / 100.0 32 | if u > 0 and c < zero_count * 0.1: 33 | high_val = u / 100.0 34 | break 35 | img_retinex[:, :, i] = np.maximum(np.minimum(img_retinex[:, :, i], high_val), low_val) 36 | 37 | img_retinex[:, :, i] = (img_retinex[:, :, i] - np.min(img_retinex[:, :, i])) / \ 38 | (np.max(img_retinex[:, :, i]) - np.min(img_retinex[:, :, i])) \ 39 | * 255 40 | img_retinex = np.uint8(img_retinex) 41 | return img_retinex 42 | 43 | 44 | 45 | def SSR(img, variance): 46 | img = np.float64(img) + 1.0 47 | img_retinex = singleScaleRetinex(img, variance) 48 | for i in range(img_retinex.shape[2]): 49 | unique, count = np.unique(np.int32(img_retinex[:, :, i] * 100), return_counts=True) 50 | for u, c in zip(unique, count): 51 | if u == 0: 52 | zero_count = c 53 | break 54 | low_val = unique[0] / 100.0 55 | high_val = unique[-1] / 100.0 56 | for u, c in zip(unique, count): 57 | if u < 0 and c < zero_count * 0.1: 58 | low_val = u / 100.0 59 | if u > 0 and c < zero_count * 0.1: 60 | high_val = u / 100.0 61 | break 62 | img_retinex[:, :, i] = np.maximum(np.minimum(img_retinex[:, :, i], high_val), low_val) 63 | 64 | img_retinex[:, :, i] = (img_retinex[:, :, i] - np.min(img_retinex[:, :, i])) / \ 65 | (np.max(img_retinex[:, :, i]) - np.min(img_retinex[:, :, i])) \ 66 | * 255 67 | img_retinex = np.uint8(img_retinex) 68 | return img_retinex 69 | 70 | 71 | variance_list=[15, 80, 30] 72 | variance=300 73 | 74 | img = cv2.imread('image.jpg') 75 | img_msr=MSR(img,variance_list) 76 | img_ssr=SSR(img, variance) 77 | 78 | cv2.imshow('Original', img) 79 | cv2.imshow('MSR', img_msr) 80 | cv2.imshow('SSR', img_ssr) 81 | cv2.imwrite('SSR.jpg', img_ssr) 82 | cv2.imwrite('MSR.jpg',img_msr) 83 | 84 | 85 | cv2.waitKey(0) 86 | cv2.destroyAllWindows() 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Retinex Image Enhancement 2 | Retinex is the theory of human color vision proposed by Edwin Land to account for color sensations in real scenes. 3 | 4 | Retinex model is 5 | based on the following three assumptions: 6 | - 1. The real world is colorless, and the color we perceive is the result of the interaction 7 | of light and matter. The water we see is colorless, but the water film-soap film is 8 | colorful, which is the result of light interference on the surface of the film. 9 | - 2. Each color region is composed of three primary colors of red, green and blue of a 10 | given wavelength; 11 | - 3. The three primary colors determine the color of each unit area. 12 | 13 | The basic theory of Retinex theory is that the color of an object is determined by the 14 | ability of the object to reflect light in long (red), medium (green), and short (blue) light, 15 | rather than by the absolute value of the intensity of the reflected light. The color of the 16 | object is not affected by the illumination non-uniformity, and the retinex is based on the 17 | consistency of color perception (color constancy). Unlike traditional linear and nonlinear 18 | methods that only enhance a certain type of image, Retinex can balance dynamic range 19 | compression, edge enhancement and color constancy, so it can adapt to different types of 20 | image enhancement. 21 | 22 | 23 | ## Environment and Library Installation 24 | The project script is implemented in python 3, with openCV and numpy libraries. 25 | Use the package manager [pip](https://pip.pypa.io/en/stable/) to install openCV and numpy. Copy paste the following commands in your terminal/power shell one after the other. 26 | 27 | ```bash 28 | pip install opencv-python 29 | ``` 30 | ```bash 31 | pip install numpy 32 | ``` 33 | ## Mode of Approach 34 | The image is first imported into script for processing. 35 | Then two functions for multiscale and single scale retinex algorithms using spatial filters 36 | are implemented. If the original image is a grayscale image: the gray value of each pixel of 37 | the image is converted from an integer (int) to a floating point (float), and converted to a 38 | logarithmic domain, If the original image is a color map: the color is divided into channels, 39 | each component pixel value is converted from an integer (int) to a floating point (float) and 40 | converted to a logarithmic domain. Then the log domain is converted into real domain for 41 | further image processing and the image is displayed. 42 | 43 | ## Results 44 | 45 | 46 |
47 |
49 |
51 |
53 |
54 |
55 |
56 | ## Contributing
57 | Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
58 |
59 |
60 | ## License
61 | The [MIT](https://choosealicense.com/licenses/mit/) License
62 |
63 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sub license, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so.
64 |
65 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
66 |
--------------------------------------------------------------------------------