This article mainly introduces image processing by ** Tone Curve **. The textbook has a Tone Curve, but no code ... It may be for those who are wondering what kind of code can be achieved.
If you don't know Tone Curve and read this article
It would be nice if you could easily find out by "Introduction" in [
Tone curve, output image (color, grayscale), conversion function I will introduce them in the order of.
Terminal: Windows 10
Console: cmd(command prompt)
python:3.6.8
Virtual environment: venv
-[** Negative / Positive Inversion ](#Negative / Positive Inversion) -[ Line-shaped tone curve ](# Line-shaped tone curve) -[Line-shaped tone curve 1](# Line-shaped tone curve 1) -[Line-shaped tone curve 2](# Line-shaped tone curve 2) -[ S-shaped tone curve ](#s-shaped tone curve) -[ Gamma conversion tone curve ](# Gamma conversion tone curve) -[ Solarization ](# Solarization) -** Posterization ** -[ 2 Threshold **](# 2 Threshold)
There are two input images as follows.
Color | Grayscale |
---|---|
For grayscale, I used OpenCV's cv2.cvtColor ()
.
How color and grayscale images change I will introduce it.
Also, if the return value from the function is read by the cv2.imwrite ()
function etc.
You can save it.
Invert the pixel value as its name suggests. (* From this, * x * in the formula is the pixel value.)
f(x) = 255 - x
input | output |
---|---|
--Grayscale
input | output |
---|---|
Conversion function
def negaPosi(frame):
return 255 - frame
I'm suffering from the previously introduced article ... If you want to see more details, I would appreciate it if you read the article.
Here, the tone curve for n = 2 is output. (* N is the value of how many times the pixel value is multiplied.)
A conversion that increases the contrast of the image.
f(x) = \begin{cases} 2 \cdot x & (x < 128) \\ 255 & (otherwise)
\end{cases}
input | output |
---|---|
--Grayscale
input | output |
---|---|
Conversion function
def toneCurve1(frame, n = 1):
look_up_table = np.zeros((256,1), dtype = 'uint8')
for i in range(256):
if i < 256 / n:
look_up_table[i][0] = i * n
else:
look_up_table[i][0] = 255
return cv2.LUT(frame, look_up_table)
This is a conversion that lowers the contrast with respect to the top.
f(x) = \begin{cases} 0 & (x < 128) \\ 2 \cdot x - 255 & (otherwise)
\end{cases}
input | output |
---|---|
--Grayscale
input | output |
---|---|
Conversion function
def toneCurve2(frame, n = 1):
look_up_table = np.zeros((256,1), dtype = 'uint8')
for i in range(256):
if i < 256 - 256 / n :
look_up_table[i][0] = 0
else:
look_up_table[i][0] = i * n - 255 * (n - 1)
return cv2.LUT(frame, look_up_table)
This S Tone Curve is brighter in bright areas Dark areas are transformations that emphasize darker.
f(x) = \frac {255}{2} \cdot \left\{\sin\left(\frac {x}{255} - \frac {1}{2}\right)\pi + 1\right\}
input | output |
---|---|
--Grayscale
input | output |
---|---|
The image is clear somewhere.
Conversion function
def sToneCurve(frame):
look_up_table = np.zeros((256,1), dtype = 'uint8')
for i in range(256):
look_up_table[i][0] = 255 * (np.sin(np.pi * (i/255 - 1/2)) + 1) / 2
return cv2.LUT(frame, look_up_table)
In the line-shaped tone curve I mentioned earlier There is a part where the shading information is lost after being converted to a constant value (0, 255). In gamma conversion, conversion can be performed while leaving the shading information of that part.
f(x) = 255 \cdot \left(\frac {x}{255}\right)^\frac{1}{\gamma}
Here are some gamma value patterns.
input | γ = 3 | γ = 2 |
---|---|---|
γ = 1 | γ = 0.5 | γ = 1 / 3 |
--Grayscale
input | γ = 3 | γ = 2 |
---|---|---|
γ = 1 | γ = 0.5 | γ = 1 / 3 |
Obviously, the image of γ = 1 and input will be the same.
Conversion function
def gammaCurve(frame, gamma = 1):
look_up_table = np.zeros((256,1), dtype = 'uint8')
for i in range(256):
look_up_table[i][0] = pow(i / 255, 1 / gamma) * 255
return cv2.LUT(frame, look_up_table)
The image looks like a mixture of negative and positive images.
The conversion formula used in my solarization is as follows.
f(x) = \frac {255}{2} \cdot \sin\left\{3\pi\left(\frac {x}{255} - \frac {1}{2}\right)\right\}
input | output |
---|---|
--Grayscale
input | output |
---|---|
Conversion function
def soralization(frame):
look_up_table = np.zeros((256,1), dtype = 'uint8')
for i in range(256):
look_up_table[i][0] = (np.sin(3 * np.pi * (i / 255 + 1 / 2 )) + 1) * 255 / 2
return cv2.LUT(frame, look_up_table)
Pixel values are gradually made constant. The image will look like a painting.
As an output, a pattern in which the pixel value is divided into 2, 3 and 4 stages is output.
input | step = 2 |
---|---|
step = 3 | step = 4 |
--Grayscale
input | step = 2 |
---|---|
step = 3 | step = 4 |
It looks like a postcard.
Conversion function
def posterization(frame, step = 4):
if 1 < step and step <= 256:
look_up_table = np.zeros((256, 1), dtype = 'uint8')
split = int(256 / (step - 1))
up = int(256 / step)
for i in range(256):
if np.trunc(i / up) * split >= 255:
look_up_table[i][0] = 255
else:
look_up_table[i][0] = np.trunc(i / up) * split
return cv2.LUT(frame, look_up_table)
else:
return frame
Probably the hardest part of coming up with this code ... If you have a better way, please teach me.
From the threshold n
** Value when small is 0 (minimum value) **
** A conversion that changes the value when it is large to 255 (maximum value) **.
I haven't used it this time, but in the cv2 library, [Binarization Function](http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc /py_thresholding/py_thresholding.html).
There are cv2.adaptiveThreshold ()
and cv2.threshold ()
.
f(x) = \begin{cases}
0 & (x < n) \\ 255 &(otherwise)
\end{cases}
This time, the output is for the threshold n = {50, 128, 200}.
input | n = 50 |
---|---|
n = 128 | n = 200 |
--Grayscale
input | n = 50 |
---|---|
n = 128 | n = 200 |
Conversion function
def threshold(frame, threshold_v = 50):
frame[frame < threshold_v] = 0
frame[frame >= threshold_v] = 255
return frame
ex.py
import cv2
import numpy as np
#Functions(abridgement)
def main():
img_path = '.\\image\\castle.jpg' #Specify the image arbitrarily
img = cv2.imread(img_path)
frame = grayScale(img)
#Call a function,Please practice.
#Example:
# cv2.imwrite('tone_changed.jpg', negaPosi(img))
if __name__ == '__main__':
main()
This time, I introduced the gradation conversion by some tone curves. Next, I'm thinking of doing image processing with filters.
You can add a UI to make it more practical.
Then: wave:
-[Computer Graphics] cv -[Image source](https://pixabay.com/en/photos/%E5%9F%8E-%E3%82%B9%E3%82%B3%E3%83%83%E3%83%88 % E3% 83% A9% E3% 83% B3% E3% 83% 89-3619698 /) (Pixabay)
-[Let's talk about the tone curve of image processing ~ LUT is amazing ~] tc
Recommended Posts