IT/AI\ML

[python/OpenCV] 이미지 처리 예제 Q21~Q25

개발자 두더지 2020. 4. 20. 19:54
728x90

문제 링크

https://github.com/yoyoyo-yo/Gasyori100knock/tree/master/Question_21_30

 

 

yoyoyo-yo/Gasyori100knock

画像処理100本ノックして画像処理を画像処理して画像処理するためのもの For Japanese, English and Chinese - yoyoyo-yo/Gasyori100knock

github.com


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

 

OpenCV Python 강좌 - 히스토그램(Histogram)

이미지에서 히스토그램을 구하는 방법과 응용으로 Histogram Equalization, CLAHE을 설명합니다. 다음 OpenCV Python 튜토리얼을 참고하여 강좌를 비정기적로 포스팅하고 있습니다. https://docs.opencv.org/4.0.0..

webnautes.tistory.com


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

 

ヒストグラム平坦化・コントラスト制限付適応ヒストグラム平坦化によるカラー画像のコントラスト補正 - Pythonでいろいろやってみる

明るい画像では明度の分布は明るい方に集中しており、暗い画像では明度は暗い方に集中しています。この明度の分布(ヒストグラム)を広げて明るさをまんべんなくする方法がヒストグラム平坦化で、画像のコントラスト調整ができます。 OpenCVではメソッドcv2.equalizeHist()を使うことで実現可能です。引数となるヒストグラムにはHSV色空間のV(Value)・明度を用い、明度のヒストグラムを平坦化します。 画像が全体的に明るい場合や全体的に暗い場合はヒストグラムが特定の範囲に偏っているため平坦化(ヒストグラ

tat-pytone.hatenablog.com

https://code-graffiti.com/histograms-with-opencv-in-python/

 

【Python】OpenCVを使ったヒストグラム – calcHist(), equalizeHist()

OpenCVを使ったPythonでの画像処理についてヒストグラムを扱います。ヒストグラムを求めるにはcalcHist()を使います。画像のコントラストを調整するのにヒストグラム平坦化があり、equalizeHist()を使います。

code-graffiti.com


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

 

yoyoyo-yo/Gasyori100knock

画像処理100本ノックして画像処理を画像処理して画像処理するためのもの For Japanese, English and Chinese - yoyoyo-yo/Gasyori100knock

github.com

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)

https://newtechnologylifestyle.net/opnecv%E3%81%A7%E3%82%AC%E3%83%B3%E3%83%9E%E8%A3%9C%E6%AD%A3%E3%82%92%E8%A1%8C%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B/

 

OpenCVでガンマ補正を行ってみる - AI人工知能テクノロジー

OpenCVでガンマ補正を行ってみる OpenCV(オープンシーヴィ)とはインテルが開発・公開したオープンソースの画像処理ライブラリとなります。ここではガンマ補正について説明します。ガンマ補正を行うことで画像を明るくしたり、暗くしたりすることが出来ます。

newtechnologylifestyle.net

위의 링크를 참고해서 작성한 코드는 아래와 같다.

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

 

Python3 & OpenCV で画像処理を学ぶ[3] 〜 トーンカーブ と LUT を理解する実装実験 - Optie研

1. はじめに 2. トーンカーブ基礎実験 2.1 トーンカーブの基礎 2.1.1 例1: $y=x$ 2.1.2 例2: S字トーンカーブ 2.1.3 例3: ガンマ変換 2.1.4 使用したコード 2.2 LUT(Look Up Table)による高速化 2.2.1 LUTとは? 2.2.2 LUTの実装 2.2.3 LUTの速度性能 3. おわりに 3.1 今後の課題 3.2 まとめと次回について 4. 参考文献 1. はじめに 本記事では、トーンカーブ(階調変換関数)を実装し、入力画像の濃淡やコント

optie.hatenablog.com


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/

 

【Python/OpenCV】画像の拡大・縮小(最近傍補間法、バイリニア補間法、バイキュービック補間法)

Python版OpenCVのcv2resizeで最近傍補間法、バイリニア補間法、バイキュービック補間法を実装し、画像のサイズを変更(拡大・縮小)する方法をソースコード付きで解説します。

algorithm.joho.info

위의 링크를 참고하여 작성한 코드는 아래에

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()
728x90