Nevar pievienot vairāk kā 25 tēmas
Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
120 rindas
3.6 KiB
120 rindas
3.6 KiB
"""OpenCV Correct Transforms.""" |
|
import math |
|
|
|
import cv2 |
|
import numpy as np |
|
from third.opencv.color_transfer import color_transfer |
|
|
|
from transform.opencv import ImageTransformOpenCV |
|
|
|
|
|
class DressToCorrect(ImageTransformOpenCV): |
|
"""Dress -> Correct [OPENCV].""" |
|
|
|
def _execute(self, *args): |
|
""" |
|
Execute dress to correct phase. |
|
|
|
:param args: <[RGB]> Image to correct |
|
:return: <RGB> image corrected |
|
""" |
|
return self.correct_color(args[0], 5) |
|
|
|
@staticmethod |
|
def correct_color(img, percent): |
|
""" |
|
Correct the color of an image. |
|
|
|
:param img: <RGB> Image to correct |
|
:param percent: <int> Percent of correction (1-100) |
|
:return <RGB>: image corrected |
|
""" |
|
if img.shape[2] != 3: |
|
raise AssertionError() |
|
if not 0 < percent <= 100: |
|
raise AssertionError() |
|
|
|
half_percent = percent / 200.0 |
|
|
|
channels = cv2.split(img) |
|
|
|
out_channels = [] |
|
for channel in channels: |
|
if len(channel.shape) != 2: |
|
raise AssertionError() |
|
# find the low and high precentile values (based on the input percentile) |
|
height, width = channel.shape |
|
vec_size = width * height |
|
flat = channel.reshape(vec_size) |
|
|
|
if len(flat.shape) != 1: |
|
raise AssertionError() |
|
|
|
flat = np.sort(flat) |
|
|
|
n_cols = flat.shape[0] |
|
|
|
low_val = flat[math.floor(n_cols * half_percent)] |
|
high_val = flat[math.ceil(n_cols * (1.0 - half_percent))] |
|
|
|
# saturate below the low percentile and above the high percentile |
|
thresholded = DressToCorrect.apply_threshold(channel, low_val, high_val) |
|
# scale the channel |
|
normalized = cv2.normalize(thresholded, thresholded.copy(), 0, 255, cv2.NORM_MINMAX) |
|
out_channels.append(normalized) |
|
|
|
return cv2.merge(out_channels) |
|
|
|
@staticmethod |
|
def apply_threshold(matrix, low_value, high_value): |
|
""" |
|
Apply a threshold on a matrix. |
|
|
|
:param matrix: <array> matrix |
|
:param low_value: <float> low value |
|
:param high_value: <float> high value |
|
:return: None |
|
""" |
|
low_mask = matrix < low_value |
|
matrix = DressToCorrect.apply_mask(matrix, low_mask, low_value) |
|
|
|
high_mask = matrix > high_value |
|
matrix = DressToCorrect.apply_mask(matrix, high_mask, high_value) |
|
|
|
return matrix |
|
|
|
@staticmethod |
|
def apply_mask(matrix, mask, fill_value): |
|
""" |
|
Apply a mask on a matrix. |
|
|
|
:param matrix: <array> matrix |
|
:param mask: <RGB> image mask |
|
:param fill_value: <> fill value |
|
:return: None |
|
""" |
|
masked = np.ma.array(matrix, mask=mask, fill_value=fill_value) |
|
return masked.filled() |
|
|
|
|
|
class ColorTransfer(ImageTransformOpenCV): |
|
"""ColorTransfer [OPENCV].""" |
|
|
|
def __init__(self, input_index=(0, -1)): |
|
""" |
|
Color Transfer constructor. |
|
|
|
:param input_index: <tuple> index where to take the inputs (default is (0,-1) |
|
for first and previous transformation) |
|
:param args: <dict> args parameter to run the image transformation (default use Conf.args) |
|
""" |
|
super().__init__(input_index=input_index) |
|
|
|
def _execute(self, *args): |
|
""" |
|
Transfers the color distribution from the source to the target. |
|
|
|
:param args: <[RGB,RGB]> Image source, Image target |
|
:return: <RGB> Color transfer image |
|
""" |
|
return color_transfer(args[0], args[1], clip=True, preserve_paper=False)
|
|
|