├── imgs ├── output.jpg ├── source.jpg └── target.jpg ├── demo_color_transfer.py ├── README.md ├── .github └── FUNDING.yml └── color_transfer_MKL.py /imgs/output.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/colour_transfer_MKL/HEAD/imgs/output.jpg -------------------------------------------------------------------------------- /imgs/source.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/colour_transfer_MKL/HEAD/imgs/source.jpg -------------------------------------------------------------------------------- /imgs/target.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahmoudnafifi/colour_transfer_MKL/HEAD/imgs/target.jpg -------------------------------------------------------------------------------- /demo_color_transfer.py: -------------------------------------------------------------------------------- 1 | import PIL.Image as Image 2 | import numpy as np 3 | from utils import color_transfer_MKL as ct 4 | 5 | main_dir = 'imgs/' 6 | source = main_dir + 'source.jpg' 7 | target = main_dir + 'target.jpg' 8 | out = main_dir + 'output.jpg' 9 | 10 | source = Image.open(source) 11 | source = np.array(source)/255 12 | target = Image.open(target) 13 | target = np.array(target)/255 14 | 15 | result = ct.color_transfer_MKL(source, target) 16 | img = Image.fromarray(np.uint8(result * 255)) 17 | img.save(out) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # colour_transfer_MKL 2 | Python implementation of [Colour transfer algorithm based on linear Monge-Kantorovitch solution](https://ieeexplore.ieee.org/abstract/document/4454269). 3 | 4 | ![example](https://user-images.githubusercontent.com/37669469/125570831-dca64404-268c-4e42-b11c-48c4229dd3c5.jpg) 5 | 6 | 7 | ``` 8 | @inproceedings{pitie2007linear, 9 | title={The linear monge-kantorovitch linear colour mapping for example-based colour transfer}, 10 | author={Piti{\'e}, Fran{\c{c}}ois and Kokaram, Anil}, 11 | booktitle={4th European conference on visual media production}, 12 | pages={1--9}, 13 | year={2007}, 14 | organization={IET} 15 | } 16 | ``` 17 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: MahmoudAfifi 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: https://www.paypal.com/paypalme/MahmoudAfifi 14 | -------------------------------------------------------------------------------- /color_transfer_MKL.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | EPS = 2.2204e-16 4 | 5 | 6 | def color_transfer_MKL(source, target): 7 | assert len(source.shape) == 3, 'Images should have 3 dimensions' 8 | assert source.shape[-1] == 3, 'Images should have 3 channels' 9 | X0 = np.reshape(source, (-1, 3), 'F') 10 | X1 = np.reshape(target, (-1, 3), 'F') 11 | A = np.cov(X0, rowvar=False) 12 | B = np.cov(X1, rowvar=False) 13 | T = MKL(A, B) 14 | mX0 = np.mean(X0, axis=0) 15 | mX1 = np.mean(X1, axis=0) 16 | XR = (X0 - mX0) @ T + mX1 17 | IR = np.reshape(XR, source.shape, 'F') 18 | IR = np.real(IR) 19 | IR[IR > 1] = 1 20 | IR[IR < 0] = 0 21 | return IR 22 | 23 | 24 | def MKL(A, B): 25 | Da2, Ua = np.linalg.eig(A) 26 | 27 | Da2 = np.diag(Da2) 28 | Da2[Da2 < 0] = 0 29 | Da = np.sqrt(Da2 + EPS) 30 | C = Da @ np.transpose(Ua) @ B @ Ua @ Da 31 | Dc2, Uc = np.linalg.eig(C) 32 | 33 | Dc2 = np.diag(Dc2) 34 | Dc2[Dc2 < 0] = 0 35 | Dc = np.sqrt(Dc2 + EPS) 36 | Da_inv = np.diag(1 / (np.diag(Da))) 37 | T = Ua @ Da_inv @ Uc @ Dc @ np.transpose(Uc) @ Da_inv @ np.transpose(Ua) 38 | return T 39 | --------------------------------------------------------------------------------