├── .DS_Store ├── .gitignore ├── README.md ├── config.json ├── data └── .gitkeep ├── retinex.py └── run.py /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InnovativeCoder/Variational_retinex_based_model/f257d64bc2d3a1a5b276a46198accf0982ca6286/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Variational Retinex-based model 2 | The model is based on an anti-spoofing algorithm for face recognition. 3 | ## Description 4 | Python implementation of multiscale retinex model. 5 | 6 | ## Requirement 7 | * Numpy 8 | * OpenCV 9 | 10 | ## Reference 11 | * [A multiscale retinex for bridging the gap between color images and the human observation of scenes] (http://ieeexplore.ieee.org/document/597272/) 12 | * [An automated multi Scale Retinex with Color Restoration for image enhancement] (http://ieeexplore.ieee.org/document/6176791/) 13 | * [Multiscale Retinex] (http://www.ipol.im/pub/art/2014/107/) 14 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "sigma_list": [15, 80, 250], 3 | "G" : 5.0, 4 | "b" : 25.0, 5 | "alpha" : 125.0, 6 | "beta" : 46.0, 7 | "low_clip" : 0.01, 8 | "high_clip" : 0.99 9 | } 10 | -------------------------------------------------------------------------------- /data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InnovativeCoder/Variational_retinex_based_model/f257d64bc2d3a1a5b276a46198accf0982ca6286/data/.gitkeep -------------------------------------------------------------------------------- /retinex.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | 4 | def singleScaleRetinex(img, sigma): 5 | 6 | retinex = np.log10(img) - np.log10(cv2.GaussianBlur(img, (0, 0), sigma)) 7 | 8 | return retinex 9 | 10 | def multiScaleRetinex(img, sigma_list): 11 | 12 | retinex = np.zeros_like(img) 13 | for sigma in sigma_list: 14 | retinex += singleScaleRetinex(img, sigma) 15 | 16 | retinex = retinex / len(sigma_list) 17 | 18 | return retinex 19 | 20 | def colorRestoration(img, alpha, beta): 21 | 22 | img_sum = np.sum(img, axis=2, keepdims=True) 23 | 24 | color_restoration = beta * (np.log10(alpha * img) - np.log10(img_sum)) 25 | 26 | return color_restoration 27 | 28 | def simplestColorBalance(img, low_clip, high_clip): 29 | 30 | total = img.shape[0] * img.shape[1] 31 | for i in range(img.shape[2]): 32 | unique, counts = np.unique(img[:, :, i], return_counts=True) 33 | current = 0 34 | for u, c in zip(unique, counts): 35 | if float(current) / total < low_clip: 36 | low_val = u 37 | if float(current) / total < high_clip: 38 | high_val = u 39 | current += c 40 | 41 | img[:, :, i] = np.maximum(np.minimum(img[:, :, i], high_val), low_val) 42 | 43 | return img 44 | 45 | def MSRCR(img, sigma_list, G, b, alpha, beta, low_clip, high_clip): 46 | 47 | img = np.float64(img) + 1.0 48 | 49 | img_retinex = multiScaleRetinex(img, sigma_list) 50 | img_color = colorRestoration(img, alpha, beta) 51 | img_msrcr = G * (img_retinex * img_color + b) 52 | 53 | for i in range(img_msrcr.shape[2]): 54 | img_msrcr[:, :, i] = (img_msrcr[:, :, i] - np.min(img_msrcr[:, :, i])) / \ 55 | (np.max(img_msrcr[:, :, i]) - np.min(img_msrcr[:, :, i])) * \ 56 | 255 57 | 58 | img_msrcr = np.uint8(np.minimum(np.maximum(img_msrcr, 0), 255)) 59 | img_msrcr = simplestColorBalance(img_msrcr, low_clip, high_clip) 60 | 61 | return img_msrcr 62 | 63 | def automatedMSRCR(img, sigma_list): 64 | 65 | img = np.float64(img) + 1.0 66 | 67 | img_retinex = multiScaleRetinex(img, sigma_list) 68 | 69 | for i in range(img_retinex.shape[2]): 70 | unique, count = np.unique(np.int32(img_retinex[:, :, i] * 100), return_counts=True) 71 | for u, c in zip(unique, count): 72 | if u == 0: 73 | zero_count = c 74 | break 75 | 76 | low_val = unique[0] / 100.0 77 | high_val = unique[-1] / 100.0 78 | for u, c in zip(unique, count): 79 | if u < 0 and c < zero_count * 0.1: 80 | low_val = u / 100.0 81 | if u > 0 and c < zero_count * 0.1: 82 | high_val = u / 100.0 83 | break 84 | 85 | img_retinex[:, :, i] = np.maximum(np.minimum(img_retinex[:, :, i], high_val), low_val) 86 | 87 | img_retinex[:, :, i] = (img_retinex[:, :, i] - np.min(img_retinex[:, :, i])) / \ 88 | (np.max(img_retinex[:, :, i]) - np.min(img_retinex[:, :, i])) \ 89 | * 255 90 | 91 | img_retinex = np.uint8(img_retinex) 92 | 93 | return img_retinex 94 | 95 | def MSRCP(img, sigma_list, low_clip, high_clip): 96 | 97 | img = np.float64(img) + 1.0 98 | 99 | intensity = np.sum(img, axis=2) / img.shape[2] 100 | 101 | retinex = multiScaleRetinex(intensity, sigma_list) 102 | 103 | intensity = np.expand_dims(intensity, 2) 104 | retinex = np.expand_dims(retinex, 2) 105 | 106 | intensity1 = simplestColorBalance(retinex, low_clip, high_clip) 107 | 108 | intensity1 = (intensity1 - np.min(intensity1)) / \ 109 | (np.max(intensity1) - np.min(intensity1)) * \ 110 | 255.0 + 1.0 111 | 112 | img_msrcp = np.zeros_like(img) 113 | 114 | for y in range(img_msrcp.shape[0]): 115 | for x in range(img_msrcp.shape[1]): 116 | B = np.max(img[y, x]) 117 | A = np.minimum(256.0 / B, intensity1[y, x, 0] / intensity[y, x, 0]) 118 | img_msrcp[y, x, 0] = A * img[y, x, 0] 119 | img_msrcp[y, x, 1] = A * img[y, x, 1] 120 | img_msrcp[y, x, 2] = A * img[y, x, 2] 121 | 122 | img_msrcp = np.uint8(img_msrcp - 1.0) 123 | 124 | return img_msrcp 125 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | import cv2 5 | import json 6 | 7 | import retinex 8 | 9 | data_path = 'data' 10 | img_list = os.listdir(data_path) 11 | if len(img_list) == 0: 12 | print 'Data directory is empty.' 13 | exit() 14 | 15 | with open('config.json', 'r') as f: 16 | config = json.load(f) 17 | 18 | for img_name in img_list: 19 | if img_name == '.gitkeep': 20 | continue 21 | 22 | img = cv2.imread(os.path.join(data_path, img_name)) 23 | 24 | img_msrcr = retinex.MSRCR( 25 | img, 26 | config['sigma_list'], 27 | config['G'], 28 | config['b'], 29 | config['alpha'], 30 | config['beta'], 31 | config['low_clip'], 32 | config['high_clip'] 33 | ) 34 | 35 | img_amsrcr = retinex.automatedMSRCR( 36 | img, 37 | config['sigma_list'] 38 | ) 39 | 40 | img_msrcp = retinex.MSRCP( 41 | img, 42 | config['sigma_list'], 43 | config['low_clip'], 44 | config['high_clip'] 45 | ) 46 | 47 | shape = img.shape 48 | cv2.imshow('Image', img) 49 | cv2.imshow('retinex', img_msrcr) 50 | cv2.imshow('Automated retinex', img_amsrcr) 51 | cv2.imshow('MSRCP', img_msrcp) 52 | cv2.waitKey() 53 | --------------------------------------------------------------------------------