diff --git a/README.md b/README.md index 43a0ebf..252d670 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The Retinex theory and algorithm mainly aims at simulating the color constancy f The light perceived by visual receptors can be separated into illuminance and reflectance. Retinex estimates the illuminance and derive the reflectance from the light, the filtered result of which is an image represents the reflectance characteristics of the scene, regardless of the illuminance. -Retinex is a very powerful filter in dynamic range compression, contrast enhancement, color constancy, etc. +Retinex is a very powerful filter in dynamic range compression, contrast enhancement, color constancy, de-fog, etc. ## MSRCP @@ -28,10 +28,12 @@ As MSRCP preserves chromaticity, it is excellent for dynamic range compression a This function accept 8-16bit integer Gray/YUV/RGB/YCoCg input. Sub-sampled format is not supported. If you want to process YUV420/YUV422 clip, convert it to YUV444 or RGB first. +For processing in YUV444 and RGB, the filtering results are different. MSR is applied to intesity channel, which is Y for YUV444 input and (R+G+B)/3 for RGB input. Since Y is a weighted average of R, G, B, processing in YUV444 may produce imbalanced chromaticity preservation. Also when chroma_protect is larger than 1 (default 1.2), the saturation of YUV444 processing result will be different from that of RGB processing result. + ### Usage ```python -retinex.MSRCP(clip input, float[] sigmaS=[25,80,250], float lower_thr=0, float upper_thr=0, bool fulls, bool fulld=fulls) +retinex.MSRCP(clip input, float[] sigmaS=[25,80,250], float lower_thr=0, float upper_thr=0, bool fulls, bool fulld=fulls, float chroma_protect=1.2) ``` - input:
@@ -58,23 +60,35 @@ retinex.MSRCP(clip input, float[] sigmaS=[25,80,250], float lower_thr=0, float u - fulld: (Default: fulls)
Determine the value range of output clip. True means full range/PC range, and False means limited range/TV range.
- Set different value for fulls and fulld will result in range conversion.
- When fulls and fulld are the same, it is safe to assign either True or False for any kinds of input clip except YUV. When fulls=False it will automatically determine the Floor and Ceil of input image, which may produce a stronger filter result under some circumstances. + Set different value for fulls and fulld will result in range conversion. + +- chroma_protect: (Default: 1.2)
+ The base of log function to attenuate chroma adjustment. It could avoid extreme chroma amplifying, while the saturation of the result is changed.
+ Available range is [1, +inf), 1 means no attenuation.
+ It is only available for YUV/YCoCg input. ### Example -TV range YUV420P8 input, filter in TV range YUV444P16 +TV range YUV420P8 input, filtered in TV range YUV444P16 with chroma protect, output TV range YUV444P16 ```python v = core.fmtc.resample(v, csp=vs.YUV444P16) -v = core.retinex.MSRCP(v) +v = core.retinex.MSRCP(v, chroma_protect=1.2) ``` -JPEG image(PC range YUV420P8 with MPEG-1 chroma placement) input, filter in PC range RGB48 +JPEG image(PC range YUV420P8 with MPEG-1 chroma placement) input, filtered in PC range YUV444P16 without chroma protect, output PC range RGB48 ```python i = core.lsmas.LWLibavSource(r'Image.jpg') i = core.fmtc.resample(i, csp=vs.YUV444P16, fulls=True, cplace="MPEG1") +i = core.retinex.MSRCP(i, fulls=True, chroma_protect=1) i = core.fmtc.matrix(i, mat="601", fulls=True, csp=vs.RGB48) +``` + +PNG image(PC range RGB24) input, filtered in PC range RGB48, output PC range RGB48 + +```python +i = core.lsmas.LWLibavSource(r'Image.png') +i = core.fmtc.bitdepth(i, bits=16) i = core.retinex.MSRCP(i) ``` diff --git a/include/MSR.h b/include/MSR.h index 619a76b..2b6b56a 100644 --- a/include/MSR.h +++ b/include/MSR.h @@ -37,8 +37,8 @@ class MSRData std::vector sigma; double lower_thr = 0; double upper_thr = 0; - int fulls = 1; - int fulld = fulls; + bool fulls = true; + bool fulld = fulls; int process[3]; @@ -60,9 +60,9 @@ class MSRData void fulls_select() { if (vi->format->colorFamily == cmGray || vi->format->colorFamily == cmYUV) - fulls = 0; + fulls = false; else if (vi->format->colorFamily == cmRGB || vi->format->colorFamily == cmYCoCg) - fulls = 1; + fulls = true; } }; diff --git a/include/MSRCP.h b/include/MSRCP.h index b2440f1..80f02c6 100644 --- a/include/MSRCP.h +++ b/include/MSRCP.h @@ -22,7 +22,6 @@ #include "Helper.h" -#include "Specification.h" #include "MSR.h" @@ -33,19 +32,13 @@ class MSRCPData : public MSRData { public: - ColorMatrix ColorMatrix_ = ColorMatrix::Unspecified; + double chroma_protect = 1.2; public: MSRCPData(const VSAPI *_vsapi = nullptr) : MSRData(_vsapi) {} ~MSRCPData() {} - - void ColorMatrix_select() - { - if (ColorMatrix_ == ColorMatrix::Unspecified) - ColorMatrix_ = ColorMatrix_Default(vi->width, vi->height); - } }; @@ -71,14 +64,14 @@ void Retinex_MSRCP(VSFrameRef * dst, const VSFrameRef * src, const VSAPI * vsapi int sNeutral = 128 << (bps - 8); T sCeil = (1 << bps) - 1; //T sCeilC = (1 << bps) - 1; - T sRange = sCeil - sFloor; + T sRange = d.fulls ? (1 << bps) - 1 : 219 << (bps - 8); T sRangeC = d.fulls ? (1 << bps) - 1 : 224 << (bps - 8); T dFloor = d.fulld ? 0 : 16 << (bps - 8); //T dFloorC = d.fulld ? 0 : 16 << (bps - 8); int dNeutral = 128 << (bps - 8); T dCeil = d.fulld ? (1 << bps) - 1 : 235 << (bps - 8); //T dCeilC = d.fulld ? (1 << bps) - 1 : 240 << (bps - 8); - T dRange = dCeil - dFloor; + T dRange = d.fulld ? (1 << bps) - 1 : 219 << (bps - 8); T dRangeC = d.fulld ? (1 << bps) - 1 : 224 << (bps - 8); FLType sFloorFL = static_cast(sFloor); //FLType sFloorCFL = static_cast(sFloorC); @@ -140,13 +133,11 @@ void Retinex_MSRCP(VSFrameRef * dst, const VSFrameRef * src, const VSAPI * vsapi { sFloor = min; sCeil = max; - sRange = sCeil - sFloor; sFloorFL = static_cast(sFloor); //sCeilFL = static_cast(sCeil); - sRangeFL = static_cast(sRange); } - gain = 1 / sRangeFL; + gain = 1 / static_cast(sCeil - sFloor); for (j = 0; j < height; j++) { i = stride * j; @@ -157,25 +148,12 @@ void Retinex_MSRCP(VSFrameRef * dst, const VSFrameRef * src, const VSAPI * vsapi Retinex_MSR(odata, idata, d, height, width, stride); - if (d.fulld) - { - offset = FLType(0.5); - for (j = 0; j < height; j++) - { - i = stride * j; - for (upper = i + width; i < upper; i++) - Ydstp[i] = static_cast(odata[i] * dRangeFL + offset); - } - } - else + offset = dFloorFL + FLType(0.5); + for (j = 0; j < height; j++) { - offset = dFloorFL + FLType(0.5); - for (j = 0; j < height; j++) - { - i = stride * j; - for (upper = i + width; i < upper; i++) - Ydstp[i] = static_cast(odata[i] * dRangeFL + offset); - } + i = stride * j; + for (upper = i + width; i < upper; i++) + Ydstp[i] = static_cast(odata[i] * dRangeFL + offset); } } else if (fi->colorFamily == cmRGB) @@ -190,17 +168,14 @@ void Retinex_MSRCP(VSFrameRef * dst, const VSFrameRef * src, const VSAPI * vsapi Bsrcp = reinterpret_cast(vsapi->getReadPtr(src, 2)); Bdstp = reinterpret_cast(vsapi->getWritePtr(dst, 2)); - FLType Kr, Kg, Kb; - ColorMatrix_Parameter(d.ColorMatrix_, Kr, Kg, Kb); - if (d.fulls) { - gain = 1 / sRangeFL; + gain = 1 / (sRangeFL * 3); for (j = 0; j < height; j++) { i = stride * j; for (upper = i + width; i < upper; i++) - idata[i] = (Kr*Rsrcp[i] + Kg*Gsrcp[i] + Kb*Bsrcp[i]) * gain; + idata[i] = (Rsrcp[i] + Gsrcp[i] + Bsrcp[i]) * gain; } } else @@ -222,18 +197,17 @@ void Retinex_MSRCP(VSFrameRef * dst, const VSFrameRef * src, const VSAPI * vsapi { sFloor = min; sCeil = max; - sRange = sCeil - sFloor; sFloorFL = static_cast(sFloor); //sCeilFL = static_cast(sCeil); - sRangeFL = static_cast(sRange); } - gain = 1 / sRangeFL; + offset = sFloorFL * -3; + gain = 1 / (static_cast(sCeil - sFloor) * 3); for (j = 0; j < height; j++) { i = stride * j; for (upper = i + width; i < upper; i++) - idata[i] = (Kr*Rsrcp[i] + Kg*Gsrcp[i] + Kb*Bsrcp[i] - sFloorFL) * gain; + idata[i] = (Rsrcp[i] + Gsrcp[i] + Bsrcp[i] + offset) * gain; } } @@ -247,7 +221,8 @@ void Retinex_MSRCP(VSFrameRef * dst, const VSFrameRef * src, const VSAPI * vsapi i = stride * j; for (upper = i + width; i < upper; i++) { - gain = Min(sRangeFL / Max(Rsrcp[i], Max(Gsrcp[i], Bsrcp[i])), idata[i] <= 0 ? 1 : odata[i] / idata[i]); + gain = idata[i] <= 0 ? 1 : odata[i] / idata[i]; + gain = Min(sRangeFL / Max(Rsrcp[i], Max(Gsrcp[i], Bsrcp[i])), gain); Rdstp[i] = static_cast(Rsrcp[i] * gain + offset); Gdstp[i] = static_cast(Gsrcp[i] * gain + offset); Bdstp[i] = static_cast(Bsrcp[i] * gain + offset); @@ -263,7 +238,8 @@ void Retinex_MSRCP(VSFrameRef * dst, const VSFrameRef * src, const VSAPI * vsapi i = stride * j; for (upper = i + width; i < upper; i++) { - gain = Min(sRangeFL / Max(Rsrcp[i], Max(Gsrcp[i], Bsrcp[i])), idata[i] <= 0 ? 1 : odata[i] / idata[i]) * scale; + gain = idata[i] <= 0 ? 1 : odata[i] / idata[i]; + gain = Min(sRangeFL / Max(Rsrcp[i], Max(Gsrcp[i], Bsrcp[i])), gain) * scale; Rdstp[i] = static_cast((Rsrcp[i] - sFloor) * gain + offset); Gdstp[i] = static_cast((Gsrcp[i] - sFloor) * gain + offset); Bdstp[i] = static_cast((Bsrcp[i] - sFloor) * gain + offset); @@ -312,13 +288,11 @@ void Retinex_MSRCP(VSFrameRef * dst, const VSFrameRef * src, const VSAPI * vsapi { sFloor = min; sCeil = max; - sRange = sCeil - sFloor; sFloorFL = static_cast(sFloor); //sCeilFL = static_cast(sCeil); - sRangeFL = static_cast(sRange); } - gain = 1 / sRangeFL; + gain = 1 / static_cast(sCeil - sFloor); for (j = 0; j < height; j++) { i = stride * j; @@ -329,35 +303,34 @@ void Retinex_MSRCP(VSFrameRef * dst, const VSFrameRef * src, const VSAPI * vsapi Retinex_MSR(odata, idata, d, height, width, stride); - if (dRangeCFL == sRangeCFL) - { - offset = dNeutralFL + FLType(0.5); - for (j = 0; j < height; j++) - { - i = stride * j; - for (upper = i + width; i < upper; i++) - { - gain = Min(sRangeC2FL / Max(Abs(Usrcp[i] - sNeutral), Abs(Vsrcp[i] - sNeutral)), idata[i] <= 0 ? 1 : odata[i] / idata[i]); - Ydstp[i] = static_cast(odata[i] * dRangeFL + dFloorFL + FLType(0.5)); - Udstp[i] = static_cast((Usrcp[i] - sNeutral) * gain + offset); - Vdstp[i] = static_cast((Vsrcp[i] - sNeutral) * gain + offset); - } - } - } + FLType chroma_protect_mul1 = static_cast(d.chroma_protect - 1); + FLType chroma_protect_mul2 = static_cast(1 / log(d.chroma_protect)); + + int Uval, Vval; + scale = dRangeCFL / sRangeCFL; + if (d.fulld) + offset = dNeutralFL + FLType(0.499999); else - { - scale = dRangeCFL / sRangeCFL; offset = dNeutralFL + FLType(0.5); - for (j = 0; j < height; j++) + + for (j = 0; j < height; j++) + { + i = stride * j; + for (upper = i + width; i < upper; i++) { - i = stride * j; - for (upper = i + width; i < upper; i++) - { - gain = Min(sRangeC2FL / Max(Abs(Usrcp[i] - sNeutral), Abs(Vsrcp[i] - sNeutral)), idata[i] <= 0 ? 1 : odata[i] / idata[i]) * scale; - Ydstp[i] = static_cast(odata[i] * dRangeFL + dFloorFL + FLType(0.5)); - Udstp[i] = static_cast((Usrcp[i] - sNeutral) * gain + offset); - Vdstp[i] = static_cast((Vsrcp[i] - sNeutral) * gain + offset); - } + if (d.chroma_protect > 1) + gain = idata[i] <= 0 ? 1 : log(odata[i] / idata[i] * chroma_protect_mul1 + 1) * chroma_protect_mul2; + else + gain = idata[i] <= 0 ? 1 : odata[i] / idata[i]; + Uval = Usrcp[i] - sNeutral; + Vval = Vsrcp[i] - sNeutral; + if (dRangeCFL == sRangeCFL) + gain = Min(sRangeC2FL / Max(Abs(Uval), Abs(Vval)), gain); + else + gain = Min(sRangeC2FL / Max(Abs(Uval), Abs(Vval)), gain) * scale; + Ydstp[i] = static_cast(odata[i] * dRangeFL + dFloorFL + FLType(0.5)); + Udstp[i] = static_cast(Uval * gain + offset); + Vdstp[i] = static_cast(Vval * gain + offset); } } } diff --git a/include/Specification.h b/include/Specification.h deleted file mode 100644 index d2ebebd..0000000 --- a/include/Specification.h +++ /dev/null @@ -1,417 +0,0 @@ -/* -* Retinex filter - VapourSynth plugin -* Copyright (C) 2014 mawen1250 -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - - -#ifndef SPECIFICATION_H_ -#define SPECIFICATION_H_ - - -#include - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -const int HD_Width_U = 2048; -const int HD_Height_U = 1536; -const int SD_Width_U = 1024; -const int SD_Height_U = 576; - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -enum class ResLevel { - SD = 0, - HD, - UHD, - Unknown, -}; - -enum class ColorPrim { - bt709 = 1, - Unspecified = 2, - bt470m = 4, - bt470bg = 5, - smpte170m = 6, - smpte240m = 7, - film = 8, - bt2020 = 9 -}; - -enum class TransferChar { - bt709 = 1, - Unspecified = 2, - bt470m = 4, - bt470bg = 5, - smpte170m = 6, - smpte240m = 7, - linear = 8, - log100 = 9, - log316 = 10, - iec61966_2_4 = 11, - bt1361e = 12, - iec61966_2_1 = 13, - bt2020_10 = 14, - bt2020_12 = 15 -}; - -enum class ColorMatrix { - GBR = 0, - bt709 = 1, - Unspecified = 2, - fcc = 4, - bt470bg = 5, - smpte170m = 6, - smpte240m = 7, - YCgCo = 8, - bt2020nc = 9, - bt2020c = 10 -}; - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -// Parameter functions -template < typename T > -void ColorPrim_Parameter(ColorPrim _ColorPrim, T &green_x, T &green_y, T &blue_x, T &blue_y, T &red_x, T &red_y, T &white_x, T &white_y) -{ - switch (_ColorPrim) - { - case ColorPrim::bt709: - green_x = 0.300; - green_y = 0.600; - blue_x = 0.150; - blue_y = 0.060; - red_x = 0.640; - red_y = 0.330; - white_x = 0.3127; - white_y = 0.3290; - break; - case ColorPrim::bt470m: - green_x = 0.21; - green_y = 0.71; - blue_x = 0.14; - blue_y = 0.08; - red_x = 0.67; - red_y = 0.33; - white_x = 0.310; - white_y = 0.316; - break; - case ColorPrim::bt470bg: - green_x = 0.29; - green_y = 0.60; - blue_x = 0.15; - blue_y = 0.06; - red_x = 0.64; - red_y = 0.33; - white_x = 0.3127; - white_y = 0.3290; - break; - case ColorPrim::smpte170m: - green_x = 0.310; - green_y = 0.595; - blue_x = 0.155; - blue_y = 0.070; - red_x = 0.630; - red_y = 0.340; - white_x = 0.3127; - white_y = 0.3290; - break; - case ColorPrim::smpte240m: - green_x = 0.310; - green_y = 0.595; - blue_x = 0.155; - blue_y = 0.070; - red_x = 0.630; - red_y = 0.340; - white_x = 0.3127; - white_y = 0.3290; - break; - case ColorPrim::film: - green_x = 0.243; - green_y = 0.692; - blue_x = 0.145; - blue_y = 0.049; - red_x = 0.681; - red_y = 0.319; - white_x = 0.310; - white_y = 0.316; - break; - case ColorPrim::bt2020: - green_x = 0.170; - green_y = 0.797; - blue_x = 0.131; - blue_y = 0.046; - red_x = 0.708; - red_y = 0.292; - white_x = 0.3127; - white_y = 0.3290; - break; - default: - green_x = 0.300; - green_y = 0.600; - blue_x = 0.150; - blue_y = 0.060; - red_x = 0.640; - red_y = 0.330; - white_x = 0.3127; - white_y = 0.3290; - break; - } -} - -template < typename T > -void TransferChar_Parameter(TransferChar _TransferChar, T &k0, T &phi, T &alpha, T &power, T &div) -{ - switch (_TransferChar) - { - case TransferChar::bt709: - k0 = 0.018; - phi = 4.500; - alpha = 0.099; - power = 0.45; - break; - case TransferChar::bt470m: - k0 = 0; - phi = 0; - alpha = 0; - power = 1 / 2.2; - break; - case TransferChar::bt470bg: - k0 = 0; - phi = 0; - alpha = 0; - power = 1 / 2.8; - break; - case TransferChar::smpte170m: - k0 = 0.018; - phi = 4.500; - alpha = 0.099; - power = 0.45; - break; - case TransferChar::smpte240m: - k0 = 0.0228; - phi = 4.0; - alpha = 0.1115; - power = 0.45; - break; - case TransferChar::linear: - k0 = 1; - phi = 1; - alpha = 0; - power = 1; - break; - case TransferChar::log100: - k0 = 0.01; - div = 2; - break; - case TransferChar::log316: - k0 = sqrt(10.) / 1000.; - div = 2.5; - break; - case TransferChar::iec61966_2_4: - k0 = 0.018; - phi = 4.500; - alpha = 0.099; - power = 0.45; - break; - case TransferChar::bt1361e: - k0 = 0.018; - phi = 4.500; - alpha = 0.099; - power = 0.45; - break; - case TransferChar::iec61966_2_1: - k0 = 0.0031308; - phi = 12.92; - alpha = 0.055; - power = 1 / 2.4; - break; - case TransferChar::bt2020_10: - k0 = 0.018; - phi = 4.500; - alpha = 0.099; - power = 0.45; - break; - case TransferChar::bt2020_12: - k0 = 0.0181; - phi = 4.500; - alpha = 0.0993; - power = 0.45; - break; - default: - k0 = 0.0031308; - phi = 12.92; - alpha = 0.055; - power = 1 / 2.4; - break; - } -} - -template < typename T > -void ColorMatrix_Parameter(ColorMatrix _ColorMatrix, T &Kr, T &Kg, T &Kb) -{ - switch (_ColorMatrix) - { - case ColorMatrix::GBR: - Kr = 0; - Kg = 1; - Kb = 0; - break; - case ColorMatrix::bt709: - Kr = 0.2126; - Kg = 0.7152; - Kb = 0.0722; - break; - case ColorMatrix::fcc: - Kr = 0.30; - Kg = 0.59; - Kb = 0.11; - break; - case ColorMatrix::bt470bg: - Kr = 0.299; - Kg = 0.587; - Kb = 0.114; - break; - case ColorMatrix::smpte170m: - Kr = 0.299; - Kg = 0.587; - Kb = 0.114; - break; - case ColorMatrix::smpte240m: - Kr = 0.212; - Kg = 0.701; - Kb = 0.087; - break; - case ColorMatrix::YCgCo: - Kr = 0.25; - Kg = 0.50; - Kb = 0.25; - break; - case ColorMatrix::bt2020nc: - Kr = 0.2627; - Kg = 0.6780; - Kb = 0.0593; - break; - case ColorMatrix::bt2020c: - Kr = 0.2627; - Kg = 0.6780; - Kb = 0.0593; - break; - default: - Kr = 0.2126; - Kg = 0.7152; - Kb = 0.0722; - break; - } -} - -template < typename T > -void TransferChar_Parameter(TransferChar _TransferChar, T &k0, T &phi, T &alpha, T &power) -{ - T temp; - TransferChar_Parameter(_TransferChar, k0, phi, alpha, power, temp); -} - -template < typename T > -void TransferChar_Parameter(TransferChar _TransferChar, T &k0, T &div) -{ - T temp; - TransferChar_Parameter(_TransferChar, k0, temp, temp, temp, div); -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -// Default functions -inline ResLevel ResLevel_Default(int Width, int Height) -{ - if (Width > HD_Width_U || Height > HD_Height_U) return ResLevel::UHD; - if (Width > SD_Width_U || Height > SD_Height_U) return ResLevel::HD; - return ResLevel::SD; -} - -inline ColorPrim ColorPrim_Default(int Width, int Height, bool RGB) -{ - ResLevel _ResLevel = ResLevel_Default(Width, Height); - - if (RGB) return ColorPrim::bt709; - if (_ResLevel == ResLevel::UHD) return ColorPrim::bt2020; - if (_ResLevel == ResLevel::HD) return ColorPrim::bt709; - if (_ResLevel == ResLevel::SD) return ColorPrim::smpte170m; - return ColorPrim::bt709; -} - -inline TransferChar TransferChar_Default(int Width, int Height, bool RGB) -{ - ResLevel _ResLevel = ResLevel_Default(Width, Height); - - if (RGB) return TransferChar::iec61966_2_1; - if (_ResLevel == ResLevel::UHD) return TransferChar::bt2020_12; - if (_ResLevel == ResLevel::HD) return TransferChar::bt709; - if (_ResLevel == ResLevel::SD) return TransferChar::smpte170m; - return TransferChar::bt709; -} - -inline ColorMatrix ColorMatrix_Default(int Width, int Height) -{ - ResLevel _ResLevel = ResLevel_Default(Width, Height); - - if (_ResLevel == ResLevel::UHD) return ColorMatrix::bt2020nc; - if (_ResLevel == ResLevel::HD) return ColorMatrix::bt709; - if (_ResLevel == ResLevel::SD) return ColorMatrix::smpte170m; - return ColorMatrix::bt709; -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -// Conversion functions -template < typename T > -T TransferChar_gamma2linear(T data, T k0, T phi, T alpha, T power) -{ - return data < k0*phi ? data / phi : pow((data + alpha) / (1 + alpha), 1 / power); -} - -template < typename T > -T TransferChar_linear2gamma(T data, T k0, T phi, T alpha, T power) -{ - return data < k0 ? phi*data : (1 + alpha)*pow(data, power) - alpha; -} - -template < typename T > -T TransferChar_gamma2linear(T data, T k0, T div) -{ - return data == 0 ? 0 : pow(10, (data - 1)*div); -} - -template < typename T > -T TransferChar_linear2gamma(T data, T k0, T div) -{ - return data < k0 ? 0 : 1 + log10(data) / div; -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -#endif \ No newline at end of file diff --git a/msvc/Retinex.vcxproj b/msvc/Retinex.vcxproj index 667fff7..555af41 100644 --- a/msvc/Retinex.vcxproj +++ b/msvc/Retinex.vcxproj @@ -121,7 +121,6 @@ - diff --git a/msvc/Retinex.vcxproj.filters b/msvc/Retinex.vcxproj.filters index 15ab149..aa1a954 100644 --- a/msvc/Retinex.vcxproj.filters +++ b/msvc/Retinex.vcxproj.filters @@ -24,9 +24,6 @@ Header Files - - Header Files - Header Files diff --git a/source/MSRCP.cpp b/source/MSRCP.cpp index 076fedb..d3e3b0b 100644 --- a/source/MSRCP.cpp +++ b/source/MSRCP.cpp @@ -167,15 +167,23 @@ void VS_CC MSRCPCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core return; } - d.fulls = int64ToIntS(vsapi->propGetInt(in, "fulls", 0, &error)); + d.fulls = vsapi->propGetInt(in, "fulls", 0, &error) == 0 ? false : true; if (error) d.fulls_select(); - d.fulld = int64ToIntS(vsapi->propGetInt(in, "fulld", 0, &error)); + d.fulld = vsapi->propGetInt(in, "fulld", 0, &error) == 0 ? false : true; if (error) d.fulld = d.fulls; - d.ColorMatrix_select(); + d.chroma_protect = vsapi->propGetFloat(in, "chroma_protect", 0, &error); + if (error) + d.chroma_protect = 1.2; + if (d.chroma_protect < 1) + { + delete data; + vsapi->setError(out, "retinex.MSRCP: Invalid \"chroma_protect\" assigned, must be float number ranges in [1, +inf)"); + return; + } // Create filter vsapi->createFilter(in, out, "MSRCP", MSRCPInit, MSRCPGetFrame, MSRCPFree, fmParallel, 0, data, core); diff --git a/source/VSPlugin.cpp b/source/VSPlugin.cpp index f01a92c..8fdbec8 100644 --- a/source/VSPlugin.cpp +++ b/source/VSPlugin.cpp @@ -29,7 +29,7 @@ VS_EXTERNAL_API(void) VapourSynthPluginInit(VSConfigPlugin configFunc, VSRegiste "Implementation of Retinex algorithm for VapourSynth.", VAPOURSYNTH_API_VERSION, 1, plugin); - registerFunc("MSRCP", "input:clip;sigma:float[]:opt;lower_thr:float:opt;upper_thr:float:opt;fulls:int:opt;fulld:int:opt", MSRCPCreate, nullptr, plugin); + registerFunc("MSRCP", "input:clip;sigma:float[]:opt;lower_thr:float:opt;upper_thr:float:opt;fulls:int:opt;fulld:int:opt;chroma_protect:float:opt", MSRCPCreate, nullptr, plugin); }