문제 링크
https://github.com/yoyoyo-yo/Gasyori100knock/tree/master/Question_21_30
Q.21 히스토그램 정규화(ヒストグラム正規化, Histogram normalization)
히스토그램 정규화를 적용해보자.
히스토그램을 통해 이미지가 어떤 방향으로 편향되어 있는지 알 수 있다.
예를 들어 0에 가까운 화소가 많으면 이미지는 전체적으로 어둡고,
반대로 255에 가까운 화소가 많으면 이미지는 밝아진다.
히스토그램이 한쪽으로 치우쳐 있는 것을 "다이나믹 레인지가 좁다" 라고 표현한다.
이미지가 어떤 속성을 지니고 있는지 더욱 잘 시각화하기 위해,
히스토그램을 정규화, 평탄화하는 등의 작업을 거치는 것이 필요하다.
히스토그램 정규화는 농도 계조 변화(gray-scale transformation) 이라고도 불리며,
[c,d]의 화소값을 가진 이미지를 [a,b]의 레인지로 변환하는 경우에 다음과 같은 식으로 표현할 수 있다.
여기서는 imori_dark.jpg를 [0, 255]의 범위에서 변환하고, matplotlib로 분포도를 살펴보자.
A.21 히스토그램 정규화(ヒストグラム正規化, Histogram normalization)의 답안
import cv2
import numpy as np
import matplotlib.pyplot as plt
# histogram normalization
def hist_normalization(img, a=0, b=255):
# get max and min
c = img.min()
d = img.max()
out = img.copy()
# normalization
out = (b-a) / (d - c) * (out - c) + a
out[out < a] = a
out[out > b] = b
out = out.astype(np.uint8)
return out
# Read image
img = cv2.imread("assets/imori_dark.jpg").astype(np.float)
H, W, C = img.shape
# histogram normalization
out = hist_normalization(img)
# Display histogram
plt.hist(out.ravel(), bins=255, rwidth=0.8, range=(0, 255))
plt.savefig("out_his.png")
plt.show()
# Save result
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.imwrite("out.jpg", out)
<np.where()>
numpy.where()을 사용하면, Numpy 배열 ndarray에 대해 조건을 만족하는 요소를 치환하거나 특정 처리를 가능하게 한다.조건을 만족하는 요소는 인덱스(위치)를 취득하는 것도 가능하다.
numpy.where(condition[, x, y])
numpy.where()은 조건식 condition을 만족하는 경우 (True인 경우) 는 x, 만족하지 않는 경우 (False인 경우) y가 되는 ndarray를 리턴하는 함수이다. x,y를 생략한 경우에는 조건을 만족한 배열의 index를 반환한다.
https://note.nkmk.me/python-numpy-where/
<np.ma모듈>
조건식으로 표현/비표현이 가능한 플롯
np.ma모듈은 마스킹된 배열 (즉,항목이 없거나 유효하지 않는 데이터가 존재하는 배열) 이 계산에 사용되지 않도록 하는 모듈이다.m
a에 관련된 공식 문서는 아래를 참고
https://docs.scipy.org/doc/numpy/reference/maskedarray.generic.html
(cf) numpy.ma.masked_where
numpy.ma.masked_where(condition, a, copy=True)
https://docs.scipy.org/doc/numpy/reference/generated/numpy.ma.masked_where.html
<np.flatten()>
다차원 배열을 일차원배열로 변경하는 함수예를 들면 이 함수는 2차원배열로 표현되는 이미지 데이터를 1차원배열로 변환하여 SVM에 입력하는 등에 활용할 수 있다.그러나 flatten함수는 출력을 할 때 새로운 배열을 만들기 때문에 비슷한 기능을 하는 ravel함수에 비해 속도가 느리다.
https://note.nkmk.me/python-numpy-ravel-flatten/
히스토그램관련해서 잘 정리해놓은 블로그 링크
https://webnautes.tistory.com/1274
Q.22 히스토그램 조작(ヒストグラム操作)
히스토그램의 평균치를 m0=128, 표준편차를 s0=52이 되도록 조작해보자.
이것은 히스토그램의 다이나믹 레인지를 변경하는 것이 아니라,
히스토그램의 평균을 변경하는 작업임에 주의하라.
평균치 m、표준편차s를 변경하기 위해서는 다음과 같은 식을 사용한다.
A.22 히스토그램 조작(ヒストグラム操作)의 답안
import cv2
import numpy as np
import matplotlib.pyplot as plt
# histogram manipulation
def hist_mani(img, m0=128, s0=52):
m = np.mean(img)
s = np.std(img)
out = img.copy()
# normalize
out = s0 / s * (out - m) + m0
out[out < 0] = 0
out[out > 255] = 255
out = out.astype(np.uint8)
return out
# Read image
img = cv2.imread("assets/imori_dark.jpg").astype(np.float)
out = hist_mani(img)
# Display histogram
plt.hist(out.ravel(), bins=255, rwidth=0.8, range=(0, 255))
plt.savefig("out_his.png")
plt.show()
# Save result
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.imwrite("out.jpg", out)
Q.23 히스토그램 평탄화(ヒストグラム平坦化, Histogram equalization)
히스토그램 평탄화를 적용해보자.
히스토그램 평탄화란 히스그램을 평탄하게 변경하는 조작으로,
위에서 언급한 평균치나 표준편차 등을 필요로 하지 않고, 히스토그램값을 균형을 조정한다.
이것은 아래의 식과 같이 정의되어 있다.
S ... 화소치의 모든 수
Zmax ... 화소치의 최대값
h(z) ... 농도z의 수
A.23 히스토그램 평탄화(ヒストグラム平坦化, Histogram equalization)의 답안
import cv2
import numpy as np
import matplotlib.pyplot as plt
# histogram equalization
def hist_equal(img, z_max=255):
H, W, C = img.shape
S = H * W * C * 1.
out = img.copy()
sum_h = 0.
for i in range(1, 255):
ind = np.where(img == i)
sum_h += len(img[ind])
z_prime = z_max / S * sum_h
out[ind] = z_prime
out = out.astype(np.uint8)
return out
# Read image
img = cv2.imread("assets/imori.jpg").astype(np.float)
# histogram normalization
out = hist_equal(img)
# Display histogram
plt.hist(out.ravel(), bins=255, rwidth=0.8, range=(0, 255))
plt.savefig("out_his.png")
plt.show()
# Save result
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.imwrite("out.jpg", out)
https://tat-pytone.hatenablog.com/entry/2019/06/30/083010
https://code-graffiti.com/histograms-with-opencv-in-python/
Q.24 감마 보정(ガンマ補正, Gamma correction)
imori_gamma.jpg에 대해 감마보정을 적용해보자.
감마 보정이란 , 카메라 등의 매체의 경유에 의해 화소값이 비선형적으로 변환하는 경우를 일컫는다.
디스플레이 등에서 이미지를 그대로 표시하면 화면이 어두워지기 때문에,
RGB의 값을 미리 크게 변환하여 앞서 말한 디스플레이의 특성을 극복하기 위한 보정의 한 방법이다.
비선형 변환은 다음의 식이 적용된다.
단, x는 [0,1]로 정규화되어 있는 것이며, c는 상수, g는 감마의 특성 (일반적으로 2.2)
그리고 감마보정은 다음의 식이 적용된다.
A.24 감마 보정(ガンマ補正, Gamma correction)의 답안
코드 작성 전에 아래의 깃 허브 주소에서 imori_gamma.jpg를 다운로드 받아 assets파일에 저장하자.
https://github.com/yoyoyo-yo/Gasyori100knock/blob/master/Question_21_30/imori_gamma.jpg
import cv2
import numpy as np
import matplotlib.pyplot as plt
# gamma correction
def gamma_correction(img, c=1, g=2.2):
out = img.copy()
out /= 255.
out = (1/c * out) ** (1/g)
out *= 255
out = out.astype(np.uint8)
return out
# Read image
img = cv2.imread("assets/imori_gamma.jpg").astype(np.float)
# Gammma correction
out = gamma_correction(img)
# Save result
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.imwrite("out.jpg", out)
위의 링크를 참고해서 작성한 코드는 아래와 같다.
import cv2
import numpy as np
gamma = 2.2
gamma_cvt = np.zeros((256,1),dtype = 'uint8')
for i in range(256):
gamma_cvt[i][0] = 255 * (float(i)/255) ** (1.0/gamma)
img_org = cv2.imread("assets/imori_gamma.jpg")
img_gamma = cv2.LUT(img_org,gamma_cvt)
cv2.imshow("original",img_org)
cv2.imshow("gamma",img_gamma)
cv2.waitKey(0)
cv2.destroyAllWindows()
<cv2.LUT()>
LUT는 Look Up Table의 약자로 화소값 0~255의 각 입력치에 대해 출력치가 0~255 중 어디에 속하는지를 미리 표로 작성해,
이미지의 농도 변환을 할 때 하나 하나 계산하지 않고 표의 값을 참조하도록 하여 계산량을 줄이는 방법이다
예를 들어 화소값을 반으로 하는 경우, LUT는 다음과 같이 표를 작성한다.
입력값 | 출력값 |
0 | 0 |
1 | 0 |
... | ... |
127 | 63 |
... | ... |
255 | 277 |
HD사이즈(1280*720)의 경우, 화소값이 921600개이므로, 이미지의 농도 변환을 하기 위해 보통 계산을 921600회 실시하게 된다. LUT를 사용하면 '256회 계산' + '921600회의 참고'가 되므로 계산하는 데 드는 비용을 줄일 수 있다. 감마보간법 등, 계산식이 복잡할수록 효과가 커진다.
http://optie.hatenablog.com/entry/2018/03/03/141427#221-LUT%E3%81%A8%E3%81%AF
Q.25 최근방보간법(最近傍補間, Nearest Neighbor)
최근방보간를 이용해 이미지가 1.5배 확장시켜보자.
최근방 보간은 이미지의 확대할 때, 최근방에 있는 화소를 그대로 사용하는 것이다.
이미지 확대하는 여러 방법 중 심플하고 처리속도가 빠르다는 장점이 있지만, 화질이 급격하게 떨어지는 것이 단점이다.
다음의 식으로 보간된다.
- I' ...확대 후의 이미지
- I ... 확대 전의 이미지
- a ... 확대률
- [ ] ... 반올림
A.25 최근방이웃 보간법(最近傍補間, Nearest Neighbor)의 답안
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Nereset Neighbor interpolation
def nn_interpolate(img, ax=1, ay=1):
H, W, C = img.shape
aH = int(ay * H)
aW = int(ax * W)
y = np.arange(aH).repeat(aW).reshape(aH, -1)
x = np.tile(np.arange(aW), (aH, 1))
y = np.round(y / ay).astype(np.int)
x = np.round(x / ax).astype(np.int)
out = img[y,x]
out = out.astype(np.uint8)
return out
# Read image
img = cv2.imread("assets/imori.jpg").astype(np.float)
# Nearest Neighbor
out = nn_interpolate(img, ax=1.5, ay=1.5)
# Save result
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.imwrite("out.jpg", out)
https://algorithm.joho.info/programming/python/opencv-resize-nearest-interpolation-py/
위의 링크를 참고하여 작성한 코드는 아래에
import cv2
import numpy as NumPy
img = cv2.imread("assets/imori.jpg")
out = cv2.resize(
img, (img.shape[1]*2, img.shape[0]*2), interpolation=cv2.INTER_NEAREST)
cv2.imshow("result",out)
cv2.waitKey(0)
cv2.destroyAllWindows()
'IT > AI\ML' 카테고리의 다른 글
[python/OpenCV] 이미지 처리 예제 Q31~Q35 (1) | 2020.04.20 |
---|---|
[python/OpenCV] 이미지 처리 예제 Q26~Q30 (0) | 2020.04.20 |
[python/OpenCV] 이미지 처리 예제 Q16~Q20 (0) | 2020.04.20 |
[python/OpenCV] 이미지 처리 예제 Q11~Q15 (0) | 2020.04.20 |
[python/OpenCV] 이미지 처리 예제 Q06~Q10 (0) | 2020.04.20 |