SHOW:
|
|
- or go back to the newest paste.
1 | - | /* ResizeX v1.0.1 mod 8 |
1 | + | /* ResizeX v1.0.1 mod 9 |
2 | ||
3 | ResizeX is a wrapper function for AviSynth's internal resizers and Dither_resize16 | |
4 | that corrects for the chroma shift caused by the internal resizers when they're | |
5 | used on horizontally subsampled chroma with MPEG2 placement. | |
6 | If either the lsb_in or lsb parameters are set to true, Dither_resize16 is used. | |
7 | If both are false, AviSynth's internal resizers are used. | |
8 | ||
9 | All AviSynth 2.6 colorspaces are supported. However, to use Dither_resize16 on RGB, the input | |
10 | must first be split into a Y8 clip containing the individual red, green, and blue channels. | |
11 | This can be done with the following script: | |
12 | ||
13 | ||
14 | Interleave(ShowRed("Y8"),ShowGreen("Y8"),ShowBlue("Y8")) | |
15 | ResizeX(target_width,target_height, lsb=true) | |
16 | DitherPost() | |
17 | MergeRGB(SelectEvery(3,0),SelectEvery(3,1),SelectEvery(3,2)) | |
18 | ||
19 | ||
20 | Internal and Dither_resize16 kernels: "Bicubic", "Bilinear", "Blackman", "Gauss", "Lanczos", | |
21 | "Point", "Sinc", "Spline16", "Spline36", "Spline64" | |
22 | ||
23 | Dither_resize16 only kernels: "Blackmanminlobe", "Impulse", "Rect" or "Box", "Spline" | |
24 | ||
25 | Bicubic kernel presets: "Catmull-Rom" or "CatRom", "Hermite", | |
26 | "Mitchell-Netravali" or "Mitchell", "Robidoux", "SoftCubic" | |
27 | ||
28 | The number of taps for the Blackman, Blackmanminlobe, Lanczos, Sinc, and Spline kernels | |
29 | can be set with the taps parameter or with a number after the kernel name. | |
30 | Using the latter method overrides the taps parameter. | |
31 | ||
32 | The b and c values for the Bicubic kernel can be set with the a1 and a2 parameters, respectively. | |
33 | If a Bicubic preset is used, it will override a1 and a2. | |
34 | The p value for the Gauss kernel can be set with a1. | |
35 | ||
36 | The softness of the SoftCubic preset can be set with a number after it ranging from 0 through 100. | |
37 | The default is 75. | |
38 | */ | |
39 | ||
40 | function ResizeX(clip input, int target_width, int target_height, float "src_left", float "src_top", | |
41 | \ float "src_width", float "src_height", string "kernel", int "taps", float "a1", float "a2", | |
42 | - | \ string "cplace", bool "luma", bool "chroma", bool "lsb_in", bool "lsb", bool "mt", string "mt_params", string "dither_params", bool "lsb_out", bool "desampling") { |
42 | + | \ string "cplace", bool "luma", bool "chroma", bool "lsb_in", bool "lsb", bool "mt", string "mt_params", string "dither_params", bool "lsb_out", bool "desampling", int "dither_mode") { |
43 | ||
44 | lsb_in = Default(lsb_in, false) | |
45 | lsb_out = Default(lsb_out, false) | |
46 | lsb = Default(lsb, false) | |
47 | ||
48 | lsb = (lsb_out && !lsb) || (lsb_in && !lsb) ? true : lsb | |
49 | ||
50 | iw = input.Width() | |
51 | ih = lsb_in ? input.Height()/2 : input.Height() | |
52 | ||
53 | src_left = Default(src_left, 0) | |
54 | src_top = Default(src_top, 0) | |
55 | desampling = Default(desampling, false) | |
56 | src_width = Default(src_width, desampling ? 0 : iw) | |
57 | src_height = Default(src_height, desampling ? 0 : ih) | |
58 | kernel = Default(kernel, "Spline36") | |
59 | cplace = Default(cplace, "MPEG2") | |
60 | luma = Default(luma, true) | |
61 | chroma = Default(chroma, true) | |
62 | mt = Default(mt, true) | |
63 | mt_params = Default(mt_params, "") | |
64 | dither_params = Default(dither_params , "") | |
65 | dither_mode = Default(dither_mode, 6) | |
66 | ||
67 | sisphbd = AvsPlusVersionNumber > 2294 | |
68 | ||
69 | Assert(target_width > 0, "ResizeX: target width must be greater than 0") | |
70 | Assert(target_height > 0, "ResizeX: target height must be greater than 0") | |
71 | Assert(cplace == "MPEG1" || cplace == "MPEG2", "ResizeX: cplace must be MPEG1 or MPEG2") | |
72 | lsb_native = sisphbd ? !(Input.BitsPerComponent() > 8 && (lsb)) : true | |
73 | sisphbd ? Assert(lsb_native, "lsb hack is not Compatible with native high bit depth" ) : nop() | |
74 | sisphbd ? Assert(!(Input.isYUVA() && lsb), "lsb hack is not Compatible with YUVA" ) : nop() | |
75 | ||
76 | # Set correct src_width and src_height values if the input values are zero or negative | |
77 | src_width = src_width == 0 ? desampling ? undefined : iw | |
78 | \ : src_width < 0 ? iw-src_left+src_width | |
79 | \ : src_width | |
80 | src_height = src_height == 0 ? desampling ? undefined : ih | |
81 | \ : src_height < 0 ? ih-src_top+src_height | |
82 | \ : src_height | |
83 | ||
84 | # Get the input clip's colorspace | |
85 | csp = input.PixelType() | |
86 | ||
87 | sislumaonly = sisphbd ? input.isy() : input.isy8() | |
88 | ||
89 | chroma = sislumaonly ? false : chroma | |
90 | ||
91 | chr420 = sisphbd ? input.is420() : input.isyv12() | |
92 | chr422 = sisphbd ? input.is422() : input.isYV16() | |
93 | chr444 = sisphbd ? input.is444() : input.isYV24() | |
94 | ||
95 | Assert(csp != "RGB24" && csp != "RGB32" || !lsb, "ResizeX: lsb things must be false for RGB input") | |
96 | ||
97 | # Check for subsampled chroma | |
98 | hssc12 = chr420 || chr422 || csp == "YUY2" | |
99 | hssc14 = csp == "YV411" | |
100 | vssc12 = chr420 | |
101 | ||
102 | Assert(!hssc12 || target_width%2 == 0, "ResizeX: target width of "+csp+" must be a multiple of 2") | |
103 | Assert(!hssc14 || target_width%4 == 0, "ResizeX: target width of "+csp+" must be a multiple of 4") | |
104 | Assert(!vssc12 || target_height%2 == 0, "ResizeX: target height of "+csp+" must be a multiple of 2") | |
105 | ||
106 | # Set chroma target and src values based on the subsampling ratios | |
107 | target_width_c = hssc12 ? target_width/2 : hssc14 ? target_width/4 : target_width | |
108 | target_height_c = vssc12 ? target_height/2 : target_height | |
109 | src_left_c = hssc12 ? src_left/2.0 : hssc14 ? src_left/4.0 : src_left | |
110 | src_top_c = vssc12 ? src_top/2.0 : src_top | |
111 | src_width2 = defined(src_width) ? src_width : iw | |
112 | src_height2 = defined(src_height) ? src_height : ih | |
113 | src_width_c = defined(src_width) ? hssc12 ? src_width/2.0 : hssc14 ? src_width/4.0 : src_width : src_width | |
114 | src_height_c = defined(src_height) ? vssc12 ? src_height/2.0 : src_height : src_height | |
115 | src_width_c2 = defined(src_width_c) ? src_width_c : hssc12 ? src_width2/2.0 : hssc14 ? src_width2/4.0 : src_width2 | |
116 | src_height_c2 = defined(src_height_c) ? src_height_c : vssc12 ? src_height2/2.0 : src_height2 | |
117 | ||
118 | # Add the MPEG2 chroma shift correction to the src_left_c value | |
119 | MPEG2shift = hssc12 ? 0.25*(desampling ? 1.0-Float(target_width_c)/Float(src_width_c2): 1.0-Float(src_width_c2)/Float(target_width_c)) | |
120 | \ : hssc14 ? 0.375*(desampling ? 1.0-Float(target_width_c)/Float(src_width_c2) : 1.0-Float(src_width_c2)/Float(target_width_c)) | |
121 | \ : 0 | |
122 | src_left_c = cplace == "MPEG2" && kernel.LeftStr(5) != "Point" ? src_left_c+MPEG2shift | |
123 | \ : src_left_c | |
124 | ||
125 | # Remove "Resize" from the end of the kernel string if present | |
126 | kernel = kernel.RightStr(6) == "Resize" ? kernel.LeftStr(kernel.StrLen()-6) : kernel | |
127 | ||
128 | # Support the Dither_resize16 kernel name variants when resizing 8-bit | |
129 | kernel = kernel == "Linear" ? "Bilinear" | |
130 | \ : kernel == "Cubic" ? "Bicubic" | |
131 | \ : kernel == "Gaussian" ? "Gauss" | |
132 | \ : kernel | |
133 | ||
134 | # Dither_resize16 kernels without an internal equivalent can't be used without lsb things being true | |
135 | Assert(lsb || kernel == "Spline16" || kernel == "Spline36" || kernel == "Spline64" || | |
136 | \ kernel != "Rect" && kernel != "Box" && kernel != "Blackmanminlobe" && kernel.LeftStr(6) != "Spline" && kernel != "Impulse", | |
137 | \ "ResizeX: Rect, Box, Blackmanminlobe, Spline, and Impulse kernels"+chr(10)+ | |
138 | \ "are available only when resizing for lsb things)") | |
139 | ||
140 | # Get the taps value from the kernel string if present (overrides the parameter) | |
141 | taps = kernel.LeftStr(6) == "Spline" && kernel != "Spline16" && kernel != "Spline36" && kernel != "Spline64" && | |
142 | \ kernel.StrLen() > 6 ? kernel.RightStr(kernel.StrLen()-6).Value().Int() | |
143 | \ : kernel.LeftStr(7) == "Lanczos" && kernel.StrLen() > 7 ? kernel.RightStr(kernel.StrLen()-7).Value().Int() | |
144 | \ : kernel.LeftStr(8) == "Blackman" && kernel.LeftStr(15) != "Blackmanminlobe" && | |
145 | \ kernel.StrLen() > 8 ? kernel.RightStr(kernel.StrLen()-8).Value().Int() | |
146 | \ : kernel.LeftStr(15) == "Blackmanminlobe" && kernel.StrLen() > 15 ? kernel.RightStr(kernel.StrLen()-15).Value().Int() | |
147 | \ : kernel.LeftStr(4) == "Sinc" && kernel.StrLen() > 4 ? kernel.RightStr(kernel.StrLen()-4).Value().Int() | |
148 | \ : taps | |
149 | ||
150 | # Remove the taps value from the kernel string if present | |
151 | kernel = kernel.LeftStr(6) == "Spline" && kernel != "Spline16" && kernel != "Spline36" && kernel != "Spline64" && | |
152 | \ kernel.StrLen() > 6 ? kernel.LeftStr(6) | |
153 | \ : kernel.LeftStr(7) == "Lanczos" && kernel.StrLen() > 7 ? kernel.LeftStr(7) | |
154 | \ : kernel.LeftStr(8) == "Blackman" && kernel.LeftStr(15) != "Blackmanminlobe" && | |
155 | \ kernel.StrLen() > 8 ? kernel.LeftStr(8) | |
156 | \ : kernel.LeftStr(15) == "Blackmanminlobe" && kernel.StrLen() > 15 ? kernel.LeftStr(15) | |
157 | \ : kernel.LeftStr(4) == "Sinc" && kernel.StrLen() > 4 ? kernel.LeftStr(4) | |
158 | \ : kernel | |
159 | ||
160 | # Set the a1 and a2 values for bicubic presets (overrides the parameters) | |
161 | kernel == "Catmull-Rom" || kernel == "CatRom" ? | |
162 | \ Eval(""" | |
163 | a1 = 0.0 | |
164 | a2 = 0.5 | |
165 | kernel = "Bicubic" | |
166 | """) | |
167 | \ : kernel == "Hermite" ? | |
168 | \ Eval(""" | |
169 | a1 = 0.0 | |
170 | a2 = 0.0 | |
171 | kernel = "Bicubic" | |
172 | """) | |
173 | \ : kernel == "Mitchell-Netravali" || kernel == "Mitchell" ? | |
174 | \ Eval(""" | |
175 | a1 = 1.0/3.0 | |
176 | a2 = 1.0/3.0 | |
177 | kernel = "Bicubic" | |
178 | """) | |
179 | \ : kernel == "Robidoux" ? | |
180 | \ Eval(""" | |
181 | a1 = 0.3782 | |
182 | a2 = 0.3109 | |
183 | kernel = "Bicubic" | |
184 | """) | |
185 | \ : kernel == "SoftCubic" ? | |
186 | \ Eval(""" | |
187 | a1 = 0.75 | |
188 | a2 = 0.25 | |
189 | kernel = "Bicubic" | |
190 | """) | |
191 | \ : kernel.LeftStr(9) == "SoftCubic" && kernel.StrLen() > 9 ? | |
192 | \ Eval(""" | |
193 | a1 = kernel.RightStr(kernel.StrLen()-9).Value() | |
194 | a1 = a1 >= 0 && a1 <= 100 ? a1/100.0 | |
195 | \ : Assert(false, "ResizeX: SoftCubic value must be in the range 0 through 100") | |
196 | a2 = 1.0-a1 | |
197 | kernel = "Bicubic" | |
198 | """) | |
199 | \ : NOP() | |
200 | ||
201 | # If chroma=false and resizing 8-bit YUV, convert to Y8 to avoid processing chroma | |
202 | csp2 = !chroma && !lsb && !(input.isrgb()) ? "Y" : csp | |
203 | input2 = csp2 == "Y" && !sislumaonly ? sisphbd ? input.ConvertToY() : input.ConvertToY8() : input | |
204 | ||
205 | # Convert YUY2 to YV16 because Dither_resize16 only supports planar formats | |
206 | input2 = csp2 == "YUY2" ? input2.ConvertToYV16() : input2 | |
207 | ||
208 | # Dither_resize16 is used if lsb things is true, | |
209 | # so the input needs to be converted to stack16 format if lsb_in=false and lsb is used | |
210 | input2 = !lsb_in && lsb ? input2.Dither_convert_8_to_16() : input2 | |
211 | ||
212 | # Blank luma channel for luma=false | |
213 | noY = input2.BlankClip(width=target_width, height=target_height, pixel_type=sisphbd ? "Y"+string(Input.BitsPerComponent()) : "Y8", color_yuv=color_gray) | |
214 | ||
215 | # Perform resizing | |
216 | lsb ? | |
217 | \ Eval(""" | |
218 | resized = input2.Dither_resize16(target_width,target_height,src_left,src_top,src_width,src_height,kernel, | |
219 | \ taps=taps, a1=a1, a2=a2, cplace=cplace, y=luma?3:1, u=chroma?3:1, v=chroma?3:1"""+dither_params+""") | |
220 | """) | |
221 | \ : input.isRGB() || (sisphbd ? (csp2 == "Y" || input.is444() && luma) : (csp2 == "Y" || csp2 == "YV24" && luma)) ? | |
222 | \ Eval(""" | |
223 | r8 = desampling ? input2.ResizeX_deResizemt(target_width,target_height,src_left,src_top,src_width,src_height,kernel,taps,a1,a2,mt_params) : \ | |
224 | mt ? input2.ResizeX_AvsmtResize(target_width,target_height,src_left,src_top,src_width,src_height,kernel,taps,a1,a2,mt_params) : input2.ResizeX_AvsResize(target_width,target_height,src_left,src_top,src_width,src_height,kernel,taps,a1,a2) | |
225 | resized = luma || input.isRGB() ? r8 : noY | |
226 | """) | |
227 | \ : Eval(""" | |
228 | r8Y = sisphbd ? input2.ConvertToY() : input2.ConvertToY8() | |
229 | r8Y = desampling ? r8Y.ResizeX_deResizemt(target_width,target_height,src_left,src_top,src_width,src_height,kernel,taps,a1,a2,mt_params) : \ | |
230 | mt ? r8Y.ResizeX_AvsmtResize(target_width,target_height,src_left,src_top,src_width,src_height,kernel,taps,a1,a2,mt_params) : r8Y.ResizeX_AvsResize(target_width,target_height,src_left,src_top,src_width,src_height,kernel,taps,a1,a2) | |
231 | r8U = sisphbd ? input2.ExtractU() : input2.UToY8() | |
232 | r8U = desampling ? r8U.ResizeX_deResizemt(target_width_c,target_height_c,src_left_c,src_top_c,src_width_c,src_height_c,kernel,taps,a1,a2,mt_params) : \ | |
233 | mt ? r8U.ResizeX_AvsmtResize(target_width_c,target_height_c,src_left_c,src_top_c,src_width_c,src_height_c,kernel,taps,a1,a2,mt_params) : r8U.ResizeX_AvsResize(target_width_c,target_height_c,src_left_c,src_top_c,src_width_c,src_height_c,kernel,taps,a1,a2) | |
234 | r8V = sisphbd ? input2.ExtractV() : input2.VToY8() | |
235 | r8V = desampling ? r8V.ResizeX_deResizemt(target_width_c,target_height_c,src_left_c,src_top_c,src_width_c,src_height_c,kernel,taps,a1,a2,mt_params) : \ | |
236 | mt ? r8V.ResizeX_AvsmtResize(target_width_c,target_height_c,src_left_c,src_top_c,src_width_c,src_height_c,kernel,taps,a1,a2,mt_params) : r8V.ResizeX_AvsResize(target_width_c,target_height_c,src_left_c,src_top_c,src_width_c,src_height_c,kernel,taps,a1,a2) | |
237 | resized = luma ? YToUV(r8U,r8V,r8Y) | |
238 | \ : YToUV(r8U,r8V,noY) | |
239 | """) | |
240 | ||
241 | - | resized = lsb && !lsb_out ? resized.DitherPost(mode=6) : resized |
241 | + | |
242 | resized = lsb && !lsb_out ? resized.DitherPost(mode=dither_mode) : resized | |
243 | ||
244 | # Make sure the output is the same colorspace as the input | |
245 | resized = csp == "YV12" ? resized.ConvertToYV12() | |
246 | \ : csp == "YV16" ? resized.ConvertToYV16() | |
247 | \ : csp == "YUY2" ? resized.ConvertToYUY2() | |
248 | \ : csp == "YV411" ? resized.ConvertToYV411() | |
249 | \ : csp == "YV24" ? resized.ConvertToYV24() | |
250 | \ : chr420 ? resized.ConvertToYUV420() | |
251 | \ : chr422 ? resized.ConvertToYUV422() | |
252 | \ : chr444 ? resized.ConvertToYUV444() | |
253 | \ : resized | |
254 | ||
255 | resized = sisphbd ? input.IsYUVA() && !(resized.IsYUVA()) ? resized.AddAlphaPlane(mt ? input.ExtractA().ResizeX_AvsmtResize(target_width,target_height,src_left,src_top,src_width,src_height,kernel,taps,a1,a2,mt_params) : input.ExtractA().ResizeX_AvsResize(target_width,target_height,src_left,src_top,src_width,src_height,kernel,taps,a1,a2)) : resized : resized | |
256 | ||
257 | return resized | |
258 | } | |
259 | ||
260 | # Wrapper function for AviSynth's internal resizers | |
261 | function ResizeX_AvsResize(clip input, int target_width, int target_height, float "src_left", float "src_top", | |
262 | \ float "src_width", float "src_height", string "kernel", int "taps", float "a1", float "a2") { | |
263 | ||
264 | kernel = Default(kernel, "Spline36") | |
265 | ||
266 | Eval(""" | |
267 | kernel == "Spline16" || | |
268 | \ kernel == "Spline36" || | |
269 | \ kernel == "Spline64" || | |
270 | \ kernel == "Bilinear" || | |
271 | \ kernel == "Point" ? input."""+kernel+"""Resize(target_width,target_height,src_left,src_top,src_width,src_height) | |
272 | \ : kernel == "Lanczos" || | |
273 | \ kernel == "Blackman" || | |
274 | \ kernel == "Sinc" ? input."""+kernel+"""Resize(target_width,target_height,src_left,src_top,src_width,src_height,taps) | |
275 | \ : kernel == "Bicubic" ? input."""+kernel+"""Resize(target_width,target_height,a1,a2,src_left,src_top,src_width,src_height) | |
276 | \ : kernel == "Gauss" ? input."""+kernel+"""Resize(target_width,target_height,src_left,src_top,src_width,src_height,a1) | |
277 | \ : Assert(false, "ResizeX_AvsResize: invalid kernel") | |
278 | """) | |
279 | } | |
280 | ||
281 | # Wrapper function for AviSynth's mt resizers | |
282 | function ResizeX_AvsmtResize(clip input, int target_width, int target_height, float "src_left", float "src_top", | |
283 | \ float "src_width", float "src_height", string "kernel", int "taps", float "a1", float "a2", string "mt_params") { | |
284 | ||
285 | kernel = Default(kernel, "Spline36") | |
286 | mt_params = Default(mt_params, "") | |
287 | ||
288 | try { Eval(""" | |
289 | kernel == "Spline16" || | |
290 | \ kernel == "Spline36" || | |
291 | \ kernel == "Spline64" || | |
292 | \ kernel == "Bilinear" || | |
293 | \ kernel == "Point" ? input."""+kernel+"""Resizemt(target_width,target_height,src_left,src_top,src_width,src_height"""+mt_params+""") | |
294 | \ : kernel == "Lanczos" || | |
295 | \ kernel == "Blackman" || | |
296 | \ kernel == "Sinc" ? input."""+kernel+"""Resizemt(target_width,target_height,src_left,src_top,src_width,src_height,taps"""+mt_params+""") | |
297 | \ : kernel == "Bicubic" ? input."""+kernel+"""Resizemt(target_width,target_height,a1,a2,src_left,src_top,src_width,src_height"""+mt_params+""") | |
298 | \ : kernel == "Gauss" ? input."""+kernel+"""Resizemt(target_width,target_height,src_left,src_top,src_width,src_height,a1"""+mt_params+""") | |
299 | \ : Assert(false, "ResizeX_AvsmtResize: invalid kernel") | |
300 | """) | |
301 | } catch(error_msg) { input.ResizeX_AvsResize(target_width, target_height, src_left, src_top, src_width, src_height, kernel, taps, a1, a2) } | |
302 | } | |
303 | ||
304 | # Wrapper function for AviSynth's mt deresizers | |
305 | function ResizeX_deResizemt(clip input, int target_width, int target_height, float "src_left", float "src_top", | |
306 | \ float "src_width", float "src_height", string "kernel", int "taps", float "a1", float "a2", string "mt_params") { | |
307 | ||
308 | kernel = Default(kernel, "Spline36") | |
309 | mt_params = Default(mt_params, "") | |
310 | ||
311 | kernel == "Spline16" || | |
312 | \ kernel == "Spline36" || | |
313 | \ kernel == "Spline64" || | |
314 | \ kernel == "Bilinear" ? Eval("input.de"+kernel+"Resizemt(target_width,target_height,src_left,src_top,src_width,src_height"+mt_params+")") | |
315 | \ : kernel == "Lanczos" || | |
316 | \ kernel == "Blackman" || | |
317 | \ kernel == "Sinc" ? Eval("input.de"+kernel+"Resizemt(target_width,target_height,src_left,src_top,src_width,src_height,taps"+mt_params+")") | |
318 | \ : kernel == "Bicubic" ? Eval("input.de"+kernel+"Resizemt(target_width,target_height,a1,a2,src_left,src_top,src_width,src_height"+mt_params+")") | |
319 | \ : kernel == "Gauss" ? Eval("input.de"+kernel+"Resizemt(target_width,target_height,src_left,src_top,src_width,src_height,a1"+mt_params+")") | |
320 | \ : Assert(false, "ResizeX_deResizemt: invalid kernel") | |
321 | } | |
322 | ||
323 | ################ | |
324 | ||
325 | # base on dithertools avsi functions by cretindesalpes | |
326 | ||
327 | Function y_gamma_to_linear (clip src, | |
328 | \ bool "tv_range_in", bool "tv_range_out", string "curve", int "u", int "v", | |
329 | \ float "gcor", bool "sigmoid", float "thr", float "cont") | |
330 | { | |
331 | src | |
332 | linear_and_gamma (false, | |
333 | \ tv_range_in, tv_range_out, curve, u, v, | |
334 | \ gcor, sigmoid, thr, cont | |
335 | \ ) | |
336 | } | |
337 | ||
338 | Function y_linear_to_gamma (clip src, | |
339 | \ bool "tv_range_in", bool "tv_range_out", string "curve", int "u", int "v", | |
340 | \ float "gcor", bool "sigmoid", float "thr", float "cont") | |
341 | { | |
342 | src | |
343 | linear_and_gamma (true, | |
344 | \ tv_range_in, tv_range_out, curve, u, v, | |
345 | \ gcor, sigmoid, thr, cont | |
346 | \ ) | |
347 | } | |
348 | ||
349 | Function linear_and_gamma (clip src, bool l2g_flag, | |
350 | \ bool "tv_range_in", bool "tv_range_out", string "curve", int "u", int "v", | |
351 | \ float "gcor", bool "sigmoid", float "thr", float "cont") | |
352 | { | |
353 | tv_range_in = Default (tv_range_in, true) | |
354 | tv_range_out = Default (tv_range_out, true) | |
355 | curve = Default (curve, "srgb") | |
356 | u = Default (u, 2) | |
357 | v = Default (v, 2) | |
358 | gcor = Default (gcor, 1.0) | |
359 | sigmoid = Default (sigmoid, false) | |
360 | ||
361 | c_num = | |
362 | \ (curve == "srgb" ) ? 0 | |
363 | \ : (curve == "709" ) ? 1 | |
364 | \ : (curve == "601" ) ? 1 | |
365 | \ : (curve == "170" ) ? 1 | |
366 | \ : (curve == "240" ) ? 2 | |
367 | \ : (curve == "2020" ) ? 3 | |
368 | \ : (curve == "1886" ) ? 4 | |
369 | \ : (curve == "1886a") ? 5 | |
370 | \ : Assert (false, "linear_and_gamma: wrong curve value.") | |
371 | ||
372 | # BT-709/601 | |
373 | # sRGB SMPTE 170M SMPTE 240M BT-2020 BT-1886 BT-1886a | |
374 | k0 = Select (c_num, " 0.04045", " 0.081 ", " 0.0912 ", " 0.08145", "0 ", "0.35 ") | |
375 | phi = Select (c_num, "12.92 ", " 4.5 ", " 4.0 ", " 4.5 ", "4.5 ", "0.65709357") # 0.35 ^ (3.0-2.6) | |
376 | gam2 = Select (c_num, " 1 ", " 1 ", " 1 ", " 1 ", "1 ", "3.0 ") | |
377 | alpha = Select (c_num, " 0.055 ", " 0.099 ", " 0.1115 ", " 0.0993 ", "0 ", "0 ") | |
378 | gamma = Select (c_num, " 2.4 ", " 2.22222", " 2.22222", " 2.22222", "2.4 ", "2.6 ") | |
379 | ||
380 | expr = (tv_range_in) ? "x 4096 - 56064 /" : "x 65536 /" | |
381 | ||
382 | # E = (E' <= k0) ? (E' ^ gam2) / phi : ((E' + alpha) / (1 + alpha)) ^ gamma | |
383 | g2l = expr | |
384 | g2l = g2l + " " + k0 +" <= " | |
385 | \ + g2l + " " + gam2 + " ^ " + phi +" / " | |
386 | \ + g2l + " " + alpha + " + 1 " + alpha + " + / " + gamma + " ^ ?" | |
387 | g2l = (gcor != 1.0) ? g2l + " 0 >= " + g2l + " " + String (gcor) + " ^ " + g2l + " ?" : g2l | |
388 | g2l = (sigmoid) ? build_sigmoid_expr (g2l , true , thr, cont) : g2l | |
389 | ||
390 | l2g = (sigmoid) ? build_sigmoid_expr (expr, false, thr, cont) : expr | |
391 | l2g = (gcor != 1.0) ? l2g + " 0 >= " + l2g + " " + String (gcor) + " ^ " + l2g + " ?" : l2g | |
392 | # E' = (E <= k0 / phi) ? (E * phi) ^ (1 / gam2) : (E ^ (1 / gamma)) * (alpha + 1) - alpha | |
393 | l2g = l2g + " " + k0 + " " + phi + " / <= " | |
394 | \ + l2g + " " + phi + " * 1 " + gam2 + " / ^ " | |
395 | \ + l2g + " 1 " + gamma + " / ^ " + alpha + " 1 + * " + alpha + " - ?" | |
396 | ||
397 | expr = (l2g_flag) ? l2g : g2l | |
398 | expr = expr + ((tv_range_out) ? " 56064 * 4096 +" : " 65536 *") | |
399 | src.mt_lut (expr="i16 " + expr, scale_inputs=!tv_range_out || !tv_range_in ? "allf" : "all", y=3, u=u, v=v) | |
400 | } | |
401 | ||
402 | # Sigmoidal functions: | |
403 | # x0 = 1 / (1 + exp (cont * thr )) | |
404 | # x1 = 1 / (1 + exp (cont * (thr - 1))) | |
405 | # y = (1 / (1 + exp (cont * (thr - x))) - x0) / (x1 - x0) | |
406 | # x = thr - log (1 / (y * (x1 - x0) + x0) - 1) / cont | |
407 | Function build_sigmoid_expr (string in, bool inv, float "thr", float "cont") | |
408 | { | |
409 | thr = Default (thr, 0.5) | |
410 | cont = Default (cont, 6.5) | |
411 | Assert ((cont > 0), "build_sigmoid_expr: cont must be strictly positive.") | |
412 | Assert ((thr >= 0 && thr <= 1), "build_sigmoid_expr: thr must be in the 0-1 range.") | |
413 | x0v = 1 / (1 + exp (cont * thr )) | |
414 | x1v = 1 / (1 + exp (cont * (thr - 1))) | |
415 | ||
416 | x0 = String ( x0v) | |
417 | x1m0 = String (x1v - x0v) | |
418 | cont = String (cont) | |
419 | thr = String (thr) | |
420 | ||
421 | expr = (inv) | |
422 | \ ? thr + " 1 " + in + " " + x1m0 + " * " + x0 + " + 0.000001 max / 1 - 0.000001 max log " + cont + " / -" | |
423 | \ : "1 1 " + cont + " " + thr + " " + in + " - * exp + / " + x0 + " - " + x1m0 + " /" | |
424 | ||
425 | return (expr) | |
426 | } |