Spaces:
Paused
Paused
Suprhimp
commited on
Commit
•
3450e6b
1
Parent(s):
2262b5b
first commit
Browse files- Dockerfile +11 -0
- main.py +42 -0
- opengl.py +412 -0
- requirments.txt +7 -0
- utils/ColorMatrix.py +234 -0
- utils/dto.py +17 -0
- utils/s3.py +14 -0
- utils/settings.py +77 -0
Dockerfile
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.10
|
2 |
+
|
3 |
+
WORKDIR /code
|
4 |
+
|
5 |
+
COPY ./requirements.txt /code/requirements.txt
|
6 |
+
|
7 |
+
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
8 |
+
|
9 |
+
COPY . .
|
10 |
+
|
11 |
+
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860", "--worker", "2"]
|
main.py
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Annotated
|
2 |
+
|
3 |
+
from fastapi import FastAPI, File, HTTPException
|
4 |
+
from fastapi.responses import StreamingResponse
|
5 |
+
from starlette.middleware.cors import CORSMiddleware
|
6 |
+
from opengl import image_enhance
|
7 |
+
|
8 |
+
from utils.dto import ToneUpData
|
9 |
+
from utils.s3 import get_image_from_s3
|
10 |
+
|
11 |
+
|
12 |
+
app = FastAPI()
|
13 |
+
cors_options = {
|
14 |
+
"allow_methods": ["*"],
|
15 |
+
"allow_headers": ["*"],
|
16 |
+
"allow_credentials": True,
|
17 |
+
"allow_origins": [
|
18 |
+
"https://www.photio.io",
|
19 |
+
"https://dev.photio.io",
|
20 |
+
"http://localhost:3000",
|
21 |
+
"http://localhost",
|
22 |
+
"http://172.30.1.10:3000",
|
23 |
+
],
|
24 |
+
}
|
25 |
+
app.add_middleware(CORSMiddleware, **cors_options)
|
26 |
+
|
27 |
+
|
28 |
+
@app.get("/")
|
29 |
+
def read_root():
|
30 |
+
return {"Hello": "World!"}
|
31 |
+
|
32 |
+
|
33 |
+
@app.post("/tone-up")
|
34 |
+
async def remove_background(items:ToneUpData):
|
35 |
+
try:
|
36 |
+
image = get_image_from_s3(items.image_id)
|
37 |
+
out_image = image_enhance(image,items.exposure,items.saturation,items.contrast,items.brightness,items.gamma,items.shadows,items.highlights,items.whites,items.blacks,items.clarity,items.temperature,items.sharpness)
|
38 |
+
# csv_to_r2(output_image,image_id)
|
39 |
+
return {"result": out_image}
|
40 |
+
except RuntimeError as e:
|
41 |
+
raise HTTPException(status_code=422, detail=f"error occur: {e}") from e
|
42 |
+
|
opengl.py
ADDED
@@ -0,0 +1,412 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
|
3 |
+
"""
|
4 |
+
The OpenGL specification doesn't allow you to create a context without a window,
|
5 |
+
since it needs the pixel format that you set into the device context.
|
6 |
+
Actually, it is necessary to have a window handler to create a "traditional" rendering context.
|
7 |
+
It is used to fetch OpenGL information and extensions availability.
|
8 |
+
Once you got that information, you can destroy the render context and release the "dummy" window.
|
9 |
+
So, in this code, the window is created, the context is set to this window,
|
10 |
+
the image result is saved to an output image file and, then, this window is released.
|
11 |
+
"""
|
12 |
+
|
13 |
+
|
14 |
+
import glfw
|
15 |
+
from OpenGL.GL import *
|
16 |
+
import OpenGL.GL.shaders
|
17 |
+
import numpy
|
18 |
+
from PIL import Image
|
19 |
+
import base64
|
20 |
+
from io import BytesIO
|
21 |
+
from utils.settings import set_options
|
22 |
+
|
23 |
+
|
24 |
+
def image_enhance(image, exposure, saturation, contrast, brightness, gamma, shadows, highlights, whites, blacks,
|
25 |
+
clarity, temperature, sharpness):
|
26 |
+
# Initialize glfw
|
27 |
+
if not glfw.init():
|
28 |
+
print('error in init')
|
29 |
+
return
|
30 |
+
|
31 |
+
# Create window
|
32 |
+
# Size (1, 1) for show nothing in window
|
33 |
+
window = glfw.create_window(1, 1, "My OpenGL window", None, None)
|
34 |
+
# window = glfw.create_window(800, 600, "My OpenGL window", None, None)
|
35 |
+
|
36 |
+
# Terminate if any issue
|
37 |
+
if not window:
|
38 |
+
print('error in window')
|
39 |
+
glfw.terminate()
|
40 |
+
return
|
41 |
+
|
42 |
+
# Set context to window
|
43 |
+
glfw.make_context_current(window)
|
44 |
+
|
45 |
+
#
|
46 |
+
|
47 |
+
# Initial data
|
48 |
+
# Positions, colors, texture coordinates
|
49 |
+
'''
|
50 |
+
# positions colors texture coords
|
51 |
+
quad = [ -0.5, -0.5, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0,
|
52 |
+
0.5, -0.5, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0,
|
53 |
+
0.5, 0.5, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0,
|
54 |
+
-0.5, 0.5, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0]
|
55 |
+
'''
|
56 |
+
# positions colors texture coords
|
57 |
+
quad = [-1., -1., 0., 0.,
|
58 |
+
1., -1., 1., 0.,
|
59 |
+
1., 1., 1., 1.,
|
60 |
+
-1., 1., 0., 1.]
|
61 |
+
quad = numpy.array(quad, dtype=numpy.float32)
|
62 |
+
|
63 |
+
# Vertices indices order
|
64 |
+
indices = [0, 1, 2,
|
65 |
+
2, 3, 0]
|
66 |
+
indices = numpy.array(indices, dtype=numpy.uint32)
|
67 |
+
|
68 |
+
# print(quad.itemsize * len(quad))
|
69 |
+
# print(indices.itemsize * len(indices))
|
70 |
+
# print(quad.itemsize * 8)
|
71 |
+
|
72 |
+
#
|
73 |
+
|
74 |
+
# Vertex shader
|
75 |
+
vertex_shader = """
|
76 |
+
attribute vec4 a_position;
|
77 |
+
attribute vec4 a_color;
|
78 |
+
attribute vec2 a_texCoord;
|
79 |
+
varying vec2 v_texCoord;
|
80 |
+
varying vec4 v_color;
|
81 |
+
|
82 |
+
void main() {
|
83 |
+
gl_Position = a_position;
|
84 |
+
v_texCoord = a_texCoord;
|
85 |
+
v_color = vec4(a_color.rgb * a_color.a, a_color.a);
|
86 |
+
}
|
87 |
+
"""
|
88 |
+
|
89 |
+
# Fragment shader
|
90 |
+
fragment_shader = """
|
91 |
+
varying vec2 v_texCoord;
|
92 |
+
uniform sampler2D u_image;
|
93 |
+
|
94 |
+
uniform float u_gamma;
|
95 |
+
uniform float u_shadows;
|
96 |
+
uniform float u_highlights;
|
97 |
+
uniform float u_whites;
|
98 |
+
uniform float u_blacks;
|
99 |
+
|
100 |
+
uniform float u_clarity;
|
101 |
+
|
102 |
+
|
103 |
+
uniform mat4 u_colorMatrix;
|
104 |
+
uniform vec4 u_colorOffset;
|
105 |
+
|
106 |
+
uniform vec2 u_pixelDimension;
|
107 |
+
|
108 |
+
uniform mat4 u_clarityMatrix;
|
109 |
+
uniform vec4 u_clarityOffset;
|
110 |
+
|
111 |
+
uniform float u_temperature;
|
112 |
+
uniform float u_sharpness;
|
113 |
+
|
114 |
+
|
115 |
+
const vec3 warmFilter = vec3(0.93, 0.54, 0.0);
|
116 |
+
|
117 |
+
const mat3 RGBtoYIQ = mat3(0.299, 0.587, 0.114, 0.596, -0.274, -0.322, 0.212, -0.523, 0.311);
|
118 |
+
const mat3 YIQtoRGB = mat3(1.0, 0.956, 0.621, 1.0, -0.272, -0.647, 1.0, -1.105, 1.702);
|
119 |
+
|
120 |
+
|
121 |
+
const float EPSILON = 0.0000001;
|
122 |
+
|
123 |
+
vec4 unpremultiply(vec4 col) {
|
124 |
+
col.rgb /= max(col.a, EPSILON);
|
125 |
+
return col;
|
126 |
+
}
|
127 |
+
|
128 |
+
float calculateLuminance(vec3 rgb) {
|
129 |
+
// This is the luminance calculation part of the RGB to HSL formular.
|
130 |
+
vec4 p = mix(
|
131 |
+
vec4(rgb.gb, 0.0, -1.0 / 3.0),
|
132 |
+
vec4(rgb.bg, -1.0, 2.0 / 3.0),
|
133 |
+
vec4(rgb.g < rgb.b)
|
134 |
+
);
|
135 |
+
|
136 |
+
vec4 q = mix(
|
137 |
+
vec4(rgb.r, p.yzx),
|
138 |
+
vec4(p.xyw, rgb.r),
|
139 |
+
vec4(rgb.r < p.x)
|
140 |
+
);
|
141 |
+
|
142 |
+
float croma = q.x - min(q.w, q.y);
|
143 |
+
float luminance = q.x - croma * 0.5;
|
144 |
+
return luminance;
|
145 |
+
}
|
146 |
+
|
147 |
+
vec3 map(vec3 x, float in_min, float in_max, float out_min, float out_max){
|
148 |
+
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
149 |
+
}
|
150 |
+
|
151 |
+
void main() {
|
152 |
+
|
153 |
+
vec4 color = clamp(texture2D(u_image, v_texCoord), 0.0, 1.0);
|
154 |
+
color.rgb /= max(color.a, EPSILON); // Revert premultiplied alpha
|
155 |
+
|
156 |
+
// Apply gamma
|
157 |
+
if (u_gamma != 1.0) {
|
158 |
+
color.rgb = pow(color.rgb, vec3(1.0 / max(u_gamma, EPSILON)));
|
159 |
+
}
|
160 |
+
|
161 |
+
// Apply shadows and highlights
|
162 |
+
float luminance = calculateLuminance(color.rgb);
|
163 |
+
|
164 |
+
float shadow = u_shadows >= 0.0
|
165 |
+
? clamp(
|
166 |
+
pow(luminance, 1.0 / (u_shadows + 1.0))
|
167 |
+
+ pow(luminance, 2.0 / (u_shadows + 1.0)) * -0.76
|
168 |
+
- luminance
|
169 |
+
, 0.0, max(u_shadows, 1.0))
|
170 |
+
: -clamp(
|
171 |
+
pow(luminance, 1.0 / (-u_shadows + 1.0))
|
172 |
+
+ pow(luminance, 2.0 / (-u_shadows + 1.0)) * -0.76
|
173 |
+
- luminance
|
174 |
+
, 0.0, max(-u_shadows, 1.0));
|
175 |
+
|
176 |
+
float highlight = u_highlights < 0.0
|
177 |
+
? clamp(
|
178 |
+
1.0
|
179 |
+
- pow(1.0 - luminance, 1.0 / (1.0 - u_highlights))
|
180 |
+
- pow(1.0 - luminance, 2.0 / (1.0 - u_highlights)) * -0.8
|
181 |
+
- luminance
|
182 |
+
, -1.0, 0.0)
|
183 |
+
: -clamp(
|
184 |
+
1.0
|
185 |
+
- pow(1.0 - luminance, 1.0 / (1.0 + u_highlights))
|
186 |
+
- pow(1.0 - luminance, 2.0 / (1.0 + u_highlights)) * -0.8
|
187 |
+
- luminance
|
188 |
+
, -1.0, 0.0);
|
189 |
+
|
190 |
+
// Bright color need more contrast and dark color need more brightness.
|
191 |
+
// This is to keep saturatation because the color information of a dark colors is lost.
|
192 |
+
float shadowContrast = shadow * luminance * luminance;
|
193 |
+
float shadowBrightness = shadow - shadowContrast;
|
194 |
+
|
195 |
+
float offset = luminance + shadowContrast + highlight;
|
196 |
+
color.rgb = clamp(offset * ((color.rgb + shadowBrightness) / max(luminance, EPSILON)), 0.0, 1.0);
|
197 |
+
|
198 |
+
// Apply Color Matrix
|
199 |
+
color.rgb = clamp(color * u_colorMatrix + u_colorOffset, 0.0, 1.0).rgb;
|
200 |
+
color.rgb = map(color.rgb, 0.0, 1.0, u_blacks / 2.0, 1.0 + u_whites / 2.0);
|
201 |
+
color = clamp(color, 0.0, 1.0);
|
202 |
+
color.rgb *= color.a; // Reset premultiplied alpha
|
203 |
+
|
204 |
+
if (u_clarity != 0.0) {
|
205 |
+
color = unpremultiply(color);
|
206 |
+
|
207 |
+
// L = Left, R = Right, C = Center, T = Top, B = Bottom
|
208 |
+
vec4 colLB = texture2D(u_image, v_texCoord + vec2(-u_pixelDimension.x, -u_pixelDimension.y));
|
209 |
+
vec4 colLC = texture2D(u_image, v_texCoord + vec2(-u_pixelDimension.x, 0.0));
|
210 |
+
vec4 colLT = texture2D(u_image, v_texCoord + vec2(-u_pixelDimension.x, u_pixelDimension.y));
|
211 |
+
|
212 |
+
vec4 colCL = texture2D(u_image, v_texCoord + vec2( 0.0, -u_pixelDimension.y));
|
213 |
+
vec4 colCR = texture2D(u_image, v_texCoord + vec2( 0.0, u_pixelDimension.y));
|
214 |
+
|
215 |
+
vec4 colRB = texture2D(u_image, v_texCoord + vec2( u_pixelDimension.x, -u_pixelDimension.y));
|
216 |
+
vec4 colRC = texture2D(u_image, v_texCoord + vec2( u_pixelDimension.x, 0.0));
|
217 |
+
vec4 colRT = texture2D(u_image, v_texCoord + vec2( u_pixelDimension.x, u_pixelDimension.y));
|
218 |
+
|
219 |
+
vec4 mergedColor = color;
|
220 |
+
mergedColor.rgb += unpremultiply(colLB).rgb + unpremultiply(colLC).rgb + unpremultiply(colLT).rgb;
|
221 |
+
mergedColor.rgb += unpremultiply(colCL).rgb + unpremultiply(colCR).rgb;
|
222 |
+
mergedColor.rgb += unpremultiply(colRB).rgb + unpremultiply(colRC).rgb + unpremultiply(colRT).rgb;
|
223 |
+
|
224 |
+
mergedColor /= 9.0;
|
225 |
+
|
226 |
+
float grayValue = clamp(color.r * 0.3 + color.g * 0.59 + color.b * 0.1, 0.111111, 0.999999);
|
227 |
+
// 1.0 and 0.0 result in white not black, therefore we clamp
|
228 |
+
|
229 |
+
// Here we create a function that will map values below 0.1 to 0. Values above 0.2 will be mapped to 1,
|
230 |
+
// and for values between 0.1 and 0.2 it will produce a gradient.
|
231 |
+
// The funtion is mirror at 0.5, meaning values between 0.8 and 0.9 will result in a decending gradient.
|
232 |
+
// And values above 0.9 will be mapped to 0.
|
233 |
+
float frequenceFactor = min(smoothstep(1.0 - grayValue, 0.0, 0.11), smoothstep(grayValue, 0.0, 0.11));
|
234 |
+
|
235 |
+
// here we apply the high pass filter. Its strength is determined by the uniform ,
|
236 |
+
// and the frequence factor. That means the only the mid tones are affected by this filter.
|
237 |
+
// Clarity input is ranging from -1 to 1. But we want to strengthen the effect.
|
238 |
+
// Therefore we see this little magic number '3.7'.
|
239 |
+
color.rgb = clamp(color + clamp((color - mergedColor) * u_clarity * 3.7 * frequenceFactor, 0.0, 10.0), 0.0, 1.0).rgb;
|
240 |
+
|
241 |
+
// apply exposure but only to the mid tones.
|
242 |
+
color.rgb = color.rgb * pow(2.0, u_clarity * 0.27 * frequenceFactor);
|
243 |
+
|
244 |
+
// apply contrast and desaturation matrix
|
245 |
+
color.rgb = clamp(color * u_colorMatrix + u_colorOffset, 0.0, 1.0).rgb;
|
246 |
+
|
247 |
+
color.rgb *= color.a; // Premultiply alpha
|
248 |
+
color = clamp(color, 0.0, 1.0);
|
249 |
+
}
|
250 |
+
|
251 |
+
|
252 |
+
if(u_temperature != 0.0){
|
253 |
+
float temperature = u_temperature;
|
254 |
+
const float tint = 0.0;
|
255 |
+
vec4 source = color;
|
256 |
+
|
257 |
+
source.rgb /= max(source.a, EPSILON); // Revert premultiplied alpha
|
258 |
+
|
259 |
+
vec3 yiq = RGBtoYIQ * source.rgb;
|
260 |
+
yiq.b = clamp(yiq.b + tint*0.5226*0.1, -0.5226, 0.5226);
|
261 |
+
vec3 rgb = YIQtoRGB * yiq;
|
262 |
+
|
263 |
+
vec3 processed = mix(
|
264 |
+
(1.0 - 2.0 * (1.0 - rgb) * (1.0 - warmFilter)),
|
265 |
+
(2.0 * rgb * warmFilter),
|
266 |
+
vec3(rgb.r < 0.5, rgb.g < 0.5, rgb.b < 0.5)
|
267 |
+
);
|
268 |
+
|
269 |
+
color = vec4(mix(rgb, processed, temperature), source.a);
|
270 |
+
|
271 |
+
color.rgb *= color.a; // Premultiply alpha again
|
272 |
+
|
273 |
+
}
|
274 |
+
|
275 |
+
if (u_sharpness != 0.0){
|
276 |
+
float factor = mix(0.2, -1.0, float(u_sharpness > 0.0));
|
277 |
+
vec4 sharpenedColor = mix(0.2, 5.0, float(u_sharpness > 0.0)) * color;
|
278 |
+
|
279 |
+
sharpenedColor += factor * clamp(texture2D(u_image, v_texCoord + u_pixelDimension * vec2(-1.0, 0.0)), 0.0, 1.0);
|
280 |
+
sharpenedColor += factor * clamp(texture2D(u_image, v_texCoord + u_pixelDimension * vec2( 0.0, -1.0)), 0.0, 1.0);
|
281 |
+
sharpenedColor += factor * clamp(texture2D(u_image, v_texCoord + u_pixelDimension * vec2( 0.0, 1.0)), 0.0, 1.0);
|
282 |
+
sharpenedColor += factor * clamp(texture2D(u_image, v_texCoord + u_pixelDimension * vec2( 1.0, 0.0)), 0.0, 1.0);
|
283 |
+
|
284 |
+
color.rgb /= max(color.a, EPSILON); // unpremultiply
|
285 |
+
sharpenedColor.rgb /= max(sharpenedColor.a, EPSILON); // unpremultiply
|
286 |
+
|
287 |
+
sharpenedColor = clamp(sharpenedColor, 0.0, 1.0);
|
288 |
+
|
289 |
+
color = clamp(mix(color, sharpenedColor, abs(u_sharpness)), 0.0, 1.0);
|
290 |
+
|
291 |
+
color = vec4(color.rgb * color.a, color.a); // premultiply
|
292 |
+
|
293 |
+
}
|
294 |
+
|
295 |
+
|
296 |
+
gl_FragColor = color;
|
297 |
+
}
|
298 |
+
|
299 |
+
"""
|
300 |
+
|
301 |
+
#
|
302 |
+
|
303 |
+
# Compile shaders
|
304 |
+
shader = OpenGL.GL.shaders.compileProgram(OpenGL.GL.shaders.compileShader(vertex_shader, GL_VERTEX_SHADER),
|
305 |
+
OpenGL.GL.shaders.compileShader(fragment_shader, GL_FRAGMENT_SHADER))
|
306 |
+
|
307 |
+
# VBO
|
308 |
+
v_b_o = glGenBuffers(1)
|
309 |
+
glBindBuffer(GL_ARRAY_BUFFER, v_b_o)
|
310 |
+
glBufferData(GL_ARRAY_BUFFER, quad.itemsize *
|
311 |
+
len(quad), quad, GL_STATIC_DRAW)
|
312 |
+
|
313 |
+
# EBO
|
314 |
+
e_b_o = glGenBuffers(1)
|
315 |
+
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, e_b_o)
|
316 |
+
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.itemsize *
|
317 |
+
len(indices), indices, GL_STATIC_DRAW)
|
318 |
+
|
319 |
+
# Configure positions of initial data
|
320 |
+
# Configure positions of initial data
|
321 |
+
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 *
|
322 |
+
sizeof(GLfloat), ctypes.c_void_p(0))
|
323 |
+
glEnableVertexAttribArray(0)
|
324 |
+
|
325 |
+
# Configure texture coordinates of initial data
|
326 |
+
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 *
|
327 |
+
sizeof(GLfloat), ctypes.c_void_p(8))
|
328 |
+
glEnableVertexAttribArray(1)
|
329 |
+
|
330 |
+
# Texture
|
331 |
+
texture = glGenTextures(1)
|
332 |
+
# Bind texture
|
333 |
+
glBindTexture(GL_TEXTURE_2D, texture)
|
334 |
+
# Texture wrapping params
|
335 |
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
|
336 |
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
|
337 |
+
# Texture filtering params
|
338 |
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
|
339 |
+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
|
340 |
+
|
341 |
+
#
|
342 |
+
|
343 |
+
# Open image
|
344 |
+
|
345 |
+
#
|
346 |
+
# img_data = numpy.array(list(image.getdata()), numpy.uint8)
|
347 |
+
#
|
348 |
+
# flipped_image = image.transpose(Image.FLIP_TOP_BOTTOM)
|
349 |
+
# img_data = flipped_image.convert("RGBA").tobytes()
|
350 |
+
#
|
351 |
+
img_data = image.convert("RGBA").tobytes()
|
352 |
+
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width,
|
353 |
+
image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data)
|
354 |
+
# print(image.width, image.height)
|
355 |
+
|
356 |
+
#
|
357 |
+
|
358 |
+
# Create render buffer with size (image.width x image.height)
|
359 |
+
rb_obj = glGenRenderbuffers(1)
|
360 |
+
glBindRenderbuffer(GL_RENDERBUFFER, rb_obj)
|
361 |
+
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, image.width, image.height)
|
362 |
+
|
363 |
+
# Create frame buffer
|
364 |
+
fb_obj = glGenFramebuffers(1)
|
365 |
+
glBindFramebuffer(GL_FRAMEBUFFER, fb_obj)
|
366 |
+
glFramebufferRenderbuffer(
|
367 |
+
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb_obj)
|
368 |
+
|
369 |
+
# Check frame buffer (that simple buffer should not be an issue)
|
370 |
+
status = glCheckFramebufferStatus(GL_FRAMEBUFFER)
|
371 |
+
if status != GL_FRAMEBUFFER_COMPLETE:
|
372 |
+
print("incomplete framebuffer object")
|
373 |
+
|
374 |
+
#
|
375 |
+
|
376 |
+
# Install program
|
377 |
+
glUseProgram(shader)
|
378 |
+
|
379 |
+
set_options(exposure, saturation, contrast, brightness, gamma, shadows, highlights, whites, blacks,
|
380 |
+
clarity, temperature, sharpness, shader, image.width, image.height)
|
381 |
+
|
382 |
+
# Bind framebuffer and set viewport size
|
383 |
+
glBindFramebuffer(GL_FRAMEBUFFER, fb_obj)
|
384 |
+
glViewport(0, 0, image.width, image.height)
|
385 |
+
|
386 |
+
# Draw the quad which covers the entire viewport
|
387 |
+
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None)
|
388 |
+
|
389 |
+
#
|
390 |
+
|
391 |
+
# PNG
|
392 |
+
# Read the data and create the image
|
393 |
+
image_buffer = glReadPixels(
|
394 |
+
0, 0, image.width, image.height, GL_RGBA, GL_UNSIGNED_BYTE)
|
395 |
+
image_out = numpy.frombuffer(image_buffer, dtype=numpy.uint8)
|
396 |
+
image_out = image_out.reshape(image.height, image.width, 4)
|
397 |
+
glfw.terminate()
|
398 |
+
img = Image.fromarray(image_out, 'RGB')
|
399 |
+
|
400 |
+
|
401 |
+
buffered = BytesIO()
|
402 |
+
img.save(buffered, format="PNG")
|
403 |
+
img_str = base64.b64encode(buffered.getvalue())
|
404 |
+
|
405 |
+
return img_str
|
406 |
+
|
407 |
+
|
408 |
+
|
409 |
+
if __name__ == "__main__":
|
410 |
+
image = Image.open("/Users/planningo/Downloads/download.jpeg")
|
411 |
+
image_enhance(image, exposure=0, saturation=0, contrast=0, brightness=0, gamma=1, shadows=0,
|
412 |
+
highlights=0, blacks=0, whites=0, clarity=0, temperature=-1, sharpness=1)
|
requirments.txt
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
glfw
|
2 |
+
PyOpenGL
|
3 |
+
numpy
|
4 |
+
Pillow
|
5 |
+
fastapi==0.104.1
|
6 |
+
uvicorn
|
7 |
+
pydantic
|
utils/ColorMatrix.py
ADDED
@@ -0,0 +1,234 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
|
3 |
+
|
4 |
+
class ColorMatrix:
|
5 |
+
def __init__(self, a=1, b=0, c=0, d=0, e=0, f=0, g=1, h=0, i=0, j=0, k=0, l=0, m=1, n=0, o=0, p=0, q=0, r=0, s=1, t=0):
|
6 |
+
self.a = a
|
7 |
+
self.b = b
|
8 |
+
self.c = c
|
9 |
+
self.d = d
|
10 |
+
self.e = e
|
11 |
+
self.f = f
|
12 |
+
self.g = g
|
13 |
+
self.h = h
|
14 |
+
self.i = i
|
15 |
+
self.j = j
|
16 |
+
self.k = k
|
17 |
+
self.l = l
|
18 |
+
self.m = m
|
19 |
+
self.n = n
|
20 |
+
self.o = o
|
21 |
+
self.p = p
|
22 |
+
self.q = q
|
23 |
+
self.r = r
|
24 |
+
self.s = s
|
25 |
+
self.t = t
|
26 |
+
|
27 |
+
self.matrix = np.array([
|
28 |
+
[a, b, c, d, e],
|
29 |
+
[f, g, h, i, j],
|
30 |
+
[k, l, m, n, o],
|
31 |
+
[p, q, r, s, t],
|
32 |
+
[0, 0, 0, 0, 1]
|
33 |
+
])
|
34 |
+
|
35 |
+
def apply(self, color):
|
36 |
+
r = self.a * color.r + self.b * color.g + \
|
37 |
+
self.c * color.b + self.d * color.a + self.e
|
38 |
+
g = self.f * color.r + self.g * color.g + \
|
39 |
+
self.h * color.b + self.i * color.a + self.j
|
40 |
+
b = self.k * color.r + self.l * color.g + \
|
41 |
+
self.m * color.b + self.n * color.a + self.o
|
42 |
+
a = self.p * color.r + self.q * color.g + \
|
43 |
+
self.r * color.b + self.s * color.a + self.t
|
44 |
+
return Color(r, g, b, a)
|
45 |
+
|
46 |
+
def reset(self):
|
47 |
+
self.a = 1
|
48 |
+
self.b = 0
|
49 |
+
self.c = 0
|
50 |
+
self.d = 0
|
51 |
+
self.e = 0
|
52 |
+
self.f = 0
|
53 |
+
self.g = 1
|
54 |
+
self.h = 0
|
55 |
+
self.i = 0
|
56 |
+
self.j = 0
|
57 |
+
self.k = 0
|
58 |
+
self.l = 0
|
59 |
+
self.m = 1
|
60 |
+
self.n = 0
|
61 |
+
self.o = 0
|
62 |
+
self.p = 0
|
63 |
+
self.q = 0
|
64 |
+
self.r = 0
|
65 |
+
self.s = 1
|
66 |
+
self.t = 0
|
67 |
+
self.matrix = np.array([
|
68 |
+
[1, 0, 0, 0, 0],
|
69 |
+
[0, 1, 0, 0, 0],
|
70 |
+
[0, 0, 1, 0, 0],
|
71 |
+
[0, 0, 0, 1, 0],
|
72 |
+
[0, 0, 0, 0, 1]
|
73 |
+
])
|
74 |
+
|
75 |
+
def multiply(self, other):
|
76 |
+
E = other
|
77 |
+
R = self
|
78 |
+
t = E.a * R.a + E.b * R.f + E.c * R.k + E.d * R.p
|
79 |
+
i = E.a * R.b + E.b * R.g + E.c * R.l + E.d * R.q
|
80 |
+
o = E.a * R.c + E.b * R.h + E.c * R.m + E.d * R.r
|
81 |
+
n = E.a * R.d + E.b * R.i + E.c * R.n + E.d * R.s
|
82 |
+
a = E.f * R.a + E.g * R.f + E.h * R.k + E.i * R.p
|
83 |
+
l = E.f * R.b + E.g * R.g + E.h * R.l + E.i * R.q
|
84 |
+
u = E.f * R.c + E.g * R.h + E.h * R.m + E.i * R.r
|
85 |
+
c = E.f * R.d + E.g * R.i + E.h * R.n + E.i * R.s
|
86 |
+
m = E.k * R.a + E.l * R.f + E.m * R.k + E.n * R.p
|
87 |
+
h = E.k * R.b + E.l * R.g + E.m * R.l + E.n * R.q
|
88 |
+
f = E.k * R.c + E.l * R.h + E.m * R.m + E.n * R.r
|
89 |
+
b = E.k * R.d + E.l * R.i + E.m * R.n + E.n * R.s
|
90 |
+
y = E.p * R.a + E.q * R.f + E.r * R.k + E.s * R.p
|
91 |
+
T = E.p * R.b + E.q * R.g + E.r * R.l + E.s * R.q
|
92 |
+
w = E.p * R.c + E.q * R.h + E.r * R.m + E.s * R.r
|
93 |
+
k = E.p * R.d + E.q * R.i + E.r * R.n + E.s * R.s
|
94 |
+
s = E.a * R.e + E.b * R.j + E.c * R.o + E.d * R.t + E.e
|
95 |
+
d = E.f * R.e + E.g * R.j + E.h * R.o + E.i * R.t + E.j
|
96 |
+
_ = E.k * R.e + E.l * R.j + E.m * R.o + E.n * R.t + E.o
|
97 |
+
F = E.p * R.e + E.q * R.j + E.r * R.o + E.s * R.t + E.t
|
98 |
+
self.a = t
|
99 |
+
self.b = i
|
100 |
+
self.c = o
|
101 |
+
self.d = n
|
102 |
+
self.e = s
|
103 |
+
self.f = a
|
104 |
+
self.g = l
|
105 |
+
self.h = u
|
106 |
+
self.i = c
|
107 |
+
self.j = d
|
108 |
+
self.k = m
|
109 |
+
self.l = h
|
110 |
+
self.m = f
|
111 |
+
self.n = b
|
112 |
+
self.o = _
|
113 |
+
self.p = y
|
114 |
+
self.q = T
|
115 |
+
self.r = w
|
116 |
+
self.s = k
|
117 |
+
self.t = F
|
118 |
+
return self
|
119 |
+
|
120 |
+
def clone(self):
|
121 |
+
newMatrix = ColorMatrix()
|
122 |
+
newMatrix.setMatrix(
|
123 |
+
self.a,
|
124 |
+
self.b,
|
125 |
+
self.c,
|
126 |
+
self.d,
|
127 |
+
self.e,
|
128 |
+
self.f,
|
129 |
+
self.g,
|
130 |
+
self.h,
|
131 |
+
self.i,
|
132 |
+
self.j,
|
133 |
+
self.k,
|
134 |
+
self.l,
|
135 |
+
self.m,
|
136 |
+
self.n,
|
137 |
+
self.o,
|
138 |
+
self.p,
|
139 |
+
self.q,
|
140 |
+
self.r,
|
141 |
+
self.s,
|
142 |
+
self.t
|
143 |
+
)
|
144 |
+
return newMatrix
|
145 |
+
|
146 |
+
def equals(self, other):
|
147 |
+
return np.array_equal(self.matrix, other.matrix)
|
148 |
+
|
149 |
+
def get_offsets(self):
|
150 |
+
return [self.e, self.j, self.o, self.t]
|
151 |
+
|
152 |
+
def __str__(self):
|
153 |
+
return str(self.matrix)
|
154 |
+
|
155 |
+
def to_array(self):
|
156 |
+
components = [
|
157 |
+
self.a,
|
158 |
+
self.b,
|
159 |
+
self.c,
|
160 |
+
self.d,
|
161 |
+
self.e,
|
162 |
+
self.f,
|
163 |
+
self.g,
|
164 |
+
self.h,
|
165 |
+
self.i,
|
166 |
+
self.j,
|
167 |
+
self.k,
|
168 |
+
self.l,
|
169 |
+
self.m,
|
170 |
+
self.n,
|
171 |
+
self.o,
|
172 |
+
self.p,
|
173 |
+
self.q,
|
174 |
+
self.r,
|
175 |
+
self.s,
|
176 |
+
self.t,
|
177 |
+
]
|
178 |
+
return components
|
179 |
+
|
180 |
+
@staticmethod
|
181 |
+
def create_brightness_matrix(value):
|
182 |
+
matrix = ColorMatrix()
|
183 |
+
matrix.e = value
|
184 |
+
matrix.j = value
|
185 |
+
matrix.o = value
|
186 |
+
return matrix
|
187 |
+
|
188 |
+
@staticmethod
|
189 |
+
def create_contrast_matrix(value):
|
190 |
+
matrix = ColorMatrix()
|
191 |
+
i = (1 - value) / 2
|
192 |
+
matrix.a = matrix.g = matrix.m = value
|
193 |
+
matrix.e = matrix.j = matrix.o = i
|
194 |
+
return matrix
|
195 |
+
|
196 |
+
@staticmethod
|
197 |
+
def create_saturation_matrix(value=1):
|
198 |
+
matrix = ColorMatrix()
|
199 |
+
i = 1 - value
|
200 |
+
o = 0.213 * i
|
201 |
+
n = 0.715 * i
|
202 |
+
s = 0.072 * i
|
203 |
+
matrix.a = o + value
|
204 |
+
matrix.b = n
|
205 |
+
matrix.c = s
|
206 |
+
matrix.f = o
|
207 |
+
matrix.g = n + value
|
208 |
+
matrix.h = s
|
209 |
+
matrix.k = o
|
210 |
+
matrix.l = n
|
211 |
+
matrix.m = s + value
|
212 |
+
return matrix
|
213 |
+
|
214 |
+
@staticmethod
|
215 |
+
def create_exposure_matrix(value=0):
|
216 |
+
exposure = 2**value
|
217 |
+
return ColorMatrix(exposure, 0, 0, 0, 0, 0, exposure, 0, 0, 0, 0, 0, exposure, 0, 0, 0, 0, 0, 1, 0)
|
218 |
+
|
219 |
+
@staticmethod
|
220 |
+
def createLinearMatrix(value=1, offset=0):
|
221 |
+
matrix = ColorMatrix()
|
222 |
+
matrix.a = matrix.g = matrix.m = value
|
223 |
+
matrix.e = matrix.j = matrix.o = offset
|
224 |
+
return matrix
|
225 |
+
|
226 |
+
# Define the Color class if not already defined
|
227 |
+
|
228 |
+
|
229 |
+
class Color:
|
230 |
+
def __init__(self, r, g, b, a):
|
231 |
+
self.r = r
|
232 |
+
self.g = g
|
233 |
+
self.b = b
|
234 |
+
self.a = a
|
utils/dto.py
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel
|
2 |
+
|
3 |
+
|
4 |
+
class ToneUpData(BaseModel):
|
5 |
+
image_id : str
|
6 |
+
exposure : float
|
7 |
+
saturation : float
|
8 |
+
contrast : float
|
9 |
+
brightness : float
|
10 |
+
gamma : float
|
11 |
+
shadows : float
|
12 |
+
highlights : float
|
13 |
+
whites : float
|
14 |
+
blacks : float
|
15 |
+
clarity : float
|
16 |
+
temperature : float
|
17 |
+
sharpness : float
|
utils/s3.py
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import boto3
|
2 |
+
from PIL import Image
|
3 |
+
from io import BytesIO
|
4 |
+
|
5 |
+
BUCKET_NAME = 'planningo-public'
|
6 |
+
DIR_NAME = 'photio/'
|
7 |
+
|
8 |
+
s3 = boto3.client('s3', aws_access_key_id='AKIAZK42H2NEXBFJWUTD',
|
9 |
+
aws_secret_access_key='ME9BuygsJeGOCZy3kFPPiqnXTQbV9PY2Lto95bxP')
|
10 |
+
|
11 |
+
def get_image_from_s3(image_id):
|
12 |
+
base_image_data = s3.get_object(
|
13 |
+
Bucket=BUCKET_NAME, Key=f'{DIR_NAME}{image_id}.png')['Body'].read()
|
14 |
+
return Image.open(BytesIO(base_image_data))
|
utils/settings.py
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
from OpenGL.GL import *
|
3 |
+
|
4 |
+
from ColorMatrix import ColorMatrix
|
5 |
+
|
6 |
+
|
7 |
+
def set_uniform(uniform_name, value, type, shader_program):
|
8 |
+
uniform_location = glGetUniformLocation(
|
9 |
+
shader_program, f"u_{uniform_name}")
|
10 |
+
if type == '1f':
|
11 |
+
glUniform1f(uniform_location, value)
|
12 |
+
elif type == '2fv':
|
13 |
+
glUniform2fv(uniform_location, 1, (GLfloat * len(value))(*value))
|
14 |
+
elif type == '4fv':
|
15 |
+
glUniform4fv(uniform_location, 1, (GLfloat * len(value))(*value))
|
16 |
+
elif type == 'mat4':
|
17 |
+
glUniformMatrix4fv(uniform_location, 1, GL_FALSE,
|
18 |
+
(GLfloat * len(value))(*value))
|
19 |
+
|
20 |
+
|
21 |
+
def set_color_matrix_uniform(color_matrix, val_name, shader_program):
|
22 |
+
t = color_matrix
|
23 |
+
|
24 |
+
set_uniform(
|
25 |
+
f"{val_name}Matrix",
|
26 |
+
[t.a, t.b, t.c, t.d, t.f, t.g, t.h, t.i,
|
27 |
+
t.k, t.l, t.m, t.n, t.p, t.q, t.r, t.s],
|
28 |
+
'mat4',
|
29 |
+
shader_program
|
30 |
+
)
|
31 |
+
|
32 |
+
set_uniform(f"{val_name}Matrix_vec", [
|
33 |
+
t.e, t.j, t.o, t.t], '4fv', shader_program)
|
34 |
+
set_uniform(f"{val_name}Offset", color_matrix.get_offsets(),
|
35 |
+
'4fv', shader_program)
|
36 |
+
|
37 |
+
|
38 |
+
def set_options(exposure, saturation, contrast, brightness, gamma, shadows, highlights, whites, blacks,
|
39 |
+
clarity, temperature, sharpness, shader_program, canvas_width, canvas_height):
|
40 |
+
if not shader_program:
|
41 |
+
print('Shader program not initialized')
|
42 |
+
return
|
43 |
+
|
44 |
+
set_uniform('gamma', gamma, '1f', shader_program)
|
45 |
+
set_uniform('shadows', shadows, '1f', shader_program)
|
46 |
+
set_uniform('highlights', highlights, '1f', shader_program)
|
47 |
+
set_uniform('whites', whites, '1f', shader_program)
|
48 |
+
set_uniform('blacks', blacks, '1f', shader_program)
|
49 |
+
set_uniform('clarity', clarity, '1f', shader_program)
|
50 |
+
set_uniform('temperature', temperature, '1f', shader_program)
|
51 |
+
set_uniform('sharpness', sharpness, '1f', shader_program)
|
52 |
+
|
53 |
+
color_matrix = ColorMatrix()
|
54 |
+
color_matrix.multiply(ColorMatrix.create_exposure_matrix(exposure))
|
55 |
+
print(vars(color_matrix))
|
56 |
+
color_matrix.multiply(ColorMatrix.create_saturation_matrix(saturation + 1))
|
57 |
+
print(vars(color_matrix))
|
58 |
+
if contrast > 0:
|
59 |
+
contrast = contrast * 2
|
60 |
+
|
61 |
+
color_matrix.multiply(ColorMatrix.create_contrast_matrix(
|
62 |
+
contrast + 1))
|
63 |
+
print(vars(color_matrix))
|
64 |
+
color_matrix.multiply(ColorMatrix.create_brightness_matrix(brightness))
|
65 |
+
print(vars(color_matrix))
|
66 |
+
set_color_matrix_uniform(color_matrix, 'color', shader_program)
|
67 |
+
|
68 |
+
clarity_matrix = ColorMatrix()
|
69 |
+
clarity_matrix.multiply(
|
70 |
+
ColorMatrix.create_saturation_matrix(-0.3 * clarity + 1))
|
71 |
+
clarity_matrix.multiply(
|
72 |
+
ColorMatrix.create_contrast_matrix(0.1 * clarity + 1))
|
73 |
+
set_color_matrix_uniform(clarity_matrix, 'clarity', shader_program)
|
74 |
+
print('pixelDimension', [
|
75 |
+
1 / canvas_width, 1 / canvas_height])
|
76 |
+
set_uniform('pixelDimension', [
|
77 |
+
1 / canvas_width, 1 / canvas_height], '2fv', shader_program)
|