【OpenCV】個人用メモ

#結論

##HSVの中間値を求める
###内包表現はあえて使わないスタイル

```python

import cv2
import numpy as np

image = cv2.imread('./testimages/test.jpg') # ファイル読み込み

# HSVでの色抽出
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV_FULL) # 画像をHSVに変換
hue = hsv[:, :, 0]#色相Hue
sat = hsv[:, :, 1]#彩度Saturation
val = hsv[:, :, 2]#明度Value
print(hue, sat, val)
print(hue.shape, sat.shape, val.shape)
print(hue[0], sat[0], val[0])

##色相の中間値を求める
h_num = []
for h in hue:
    for hn in h:
        h_num.append(hn)
ave_h = sum(h_num)/len(h_num)
print(ave_h)

##彩度の中間値を求める
s_num = []
for s in sat:
    for sn in s:
        s_num.append(sn)
ave_s = sum(s_num)/len(s_num)
print(ave_s)

##明度の中間値を求める
v_num = []
for v in val:
    for vl in v:
        v_num.append(vl)
ave_v = sum(v_num)/len(v_num)
print(ave_v)
```

##エッジ取得処理

```python
import numpy as np
import cv2

img_BGR = cv2.imread("./testimages/test.jpg")

img_Lab = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2Lab)
img_Lab_L, img_Lab_a, img_Lab_b = cv2.split(img_Lab)

cv2.imshow("pic", img_Lab_a)
cv2.waitKey(0)
cv2.destroyAllWindows()

min_val = 30
max_val = 70
img_canny = cv2.Canny(img_Lab_a, min_val, max_val)
cv2.imshow("pic", img_canny)
cv2.waitKey(0)
cv2.destroyAllWindows()
#cv2.imwrite('out.jpg', img_canny)
```

##写真→漫画風に変換
screen.jpgの用意
![screen.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493888/6dd05bfc-8d50-f23a-463c-1153da195f50.jpeg)

```python
import cv2
import time
import numpy as np

#cap = cv2.VideoCapture(0)

# 3値化の閾値※数値は自分で調節
th1, th2 = 60, 60

#r, img = cap.read()
img = cv2.imread("./testdir/test.jpg")

# 入力画像をグレースケールで取得
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# スクリーン画像読み込み
screen = cv2.imread("screen.jpg", 0)
# スクリーン画像リサイズ
screen = cv2.resize(screen, (gray.shape[1], gray.shape[0]))
# エッジ検出と色反転
edge = 255 - cv2.Canny(gray, 80, 120)
# 画像の3値化
gray[gray <= th1] = 0
gray[gray >= th2] = 255
gray[np.where((gray > th1) & (gray < th2))] = screen[np.where((gray > th1) & (gray < th2))]

# 3値画像とエッジ画像を合わせる
gray = cv2.bitwise_and(gray, edge)

# 画像保存
cv2.imwrite("Sample.jpg", gray)
```

#汎用処理まとめ

```python
import cv2
import numpy as np

#ハイクオリティな線画抽出
def edgeDetect(image):
    # カーネルサイズの設定
    kernel5 = np.ones((5, 5), np.uint8)
    # [1] 画像のグレースケール化とノイズ除去
    gray = cv2.fastNlMeansDenoising(cv2.cvtColor(image, cv2.COLOR_BGR2GRAY), h=20)
    # [2] dilate -> diff で線抽出
    dilation = cv2.dilate(gray, kernel5, iterations=1)
    diff = cv2.subtract(dilation, gray)
    diff_inv = 255 - diff
    # [3] 線を単色 -> 2値に
    _, edge = cv2.threshold(diff_inv, 225, 255, cv2.THRESH_BINARY)
    # [4] 線画とモノクロ2値を重ねる
    edge = cv2.cvtColor(edge, cv2.COLOR_GRAY2BGR)

    return edge


#もっといい線が抽出方を利用する
def edge_detect(img):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    cv2.merge((gray, gray, gray), img)
    kernel = np.ones((4, 4), np.uint8)
    dilation = cv2.dilate(img, kernel, iterations=1)
    diff = cv2.subtract(dilation, img)
    negaposi = 255 - diff
    return negaposi


#背景の透明化
def convert_alpha(img):
    # グレースケールに変換する。
    if img.ndim == 2:# モノクロ
        gray = img
    else:
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # 2値化する。
    thresh, binary = cv2.threshold(gray, 230, 255, cv2.THRESH_BINARY_INV)

    # 輪郭を抽出する。
    contours, hierarchy = cv2.findContours(
    binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
    )

    # マスクを作成する。
    mask = np.zeros_like(binary)

    # 輪郭内部 (透明化しない画素) を255で塗りつぶす。
    cv2.drawContours(mask, contours, -1, color=255, thickness=-1)

    # RGBA に変換する。
    rgba = cv2.cvtColor(img, cv2.COLOR_RGB2RGBA)

    # マスクをアルファチャンネルに設定する。
    rgba[..., 3] = mask

    # 保存する。
    #cv2.imwrite(r"result.png", rgba)
    return img


#前景領域のカット処理
def grabcut_img(img):
    mask = np.zeros(img.shape[:2], np.uint8)

    bgdModel = np.zeros((1, 65), np.float64)
    fgdModel = np.zeros((1, 65), np.float64)

    rect = (50, 50, 450, 290)
    cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_RECT)

    mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
    img = img * mask2[:, :, np.newaxis]

    return img


#グレースケール化
def grayscale_img(bgr_img):
    img_gray = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2GRAY)
    return img_gray


"""------------    領域カット     -----------"""
#色のついてない領域を抽出する処理
def find_rect_of_target_color(image):
    #画像マスクをかけて、ノイズ除去する
    ksize = 5
    # 中央値フィルタ
    image = cv2.medianBlur(image, ksize)

    #ここで範囲指定する
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV_FULL)
    h = hsv[:, :, 0]#色相
    s = hsv[:, :, 1]#彩度
    v = hsv[:, :, 2]#明度
    mask = np.zeros(h.shape, dtype=np.uint8)
    mask[(v < 240)] = 255
    contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    rects = []
    for contour in contours:
        approx = cv2.convexHull(contour)
        rect = cv2.boundingRect(approx)
        rects.append(np.array(rect))
    return rects

#ペイント領域のカット
def rect_image(image):
    rects = find_rect_of_target_color(image)
    if len(rects) > 0:
        rect = max(rects, key=(lambda x: x[2] * x[3]))
        #cv2.rectangle(image, tuple(rect[0:2]), tuple(rect[0:2] + rect[2:4]), (0, 0, 255), thickness=2)

    #[140  26 349 262]
    cut_image = image[rect[1]:rect[3] + rect[1], rect[0]:rect[2] + rect[0]]
    return cut_image
"""--------------------------------"""

#画像表示用
def image_show(image):
    cv2.imshow("pic", image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

#固定リサイズ
def image_resize(image, size=224):
    # width = size
    # _height, _width, channels = image.shape[:3]  # 取得
    # height = width * (_height / _width)
    # image = cv2.resize(image, (width, int(height)))
    image = cv2.resize(image, (size, size))
    return image

#画像データオール
def get_all_image(image):
    image = image_resize(image)  # リサイズ
    rect_img = rect_image(image)  # 領域抽出

    rgb_img = rect_img.copy()  # 全体の画像
    gray_img = grayscale_img(rect_img)  # グレースケール
    edge_img = edge_detect(rect_img)  # 線画抽出

    return rgb_img, gray_img, edge_img

#セレクトしてゲットする
def select_image(image, param):
    image = image_resize(image)  # リサイズ
    rect_img = rect_image(image)  # 領域抽出
    if param == "color":
        rgb_img = rect_img.copy()  # 全体の画像
        return rgb_img
    elif param == "gray":
        gray_img = grayscale_img(rect_img)  # グレースケール
        return gray_img
    elif param == "edge":
        edge_img = edge_detect(rect_img)  # 線画抽出
        return edge_img

#test用
def test():
    image = cv2.imread("./testdir/test_cap2.jpg")
    image = image_resize(image)#リサイズ
    rect_img = rect_image(image)#領域抽出

    rgb_img = rect_img.copy()#全体の画像
    gray_img = grayscale_img(rect_img)#グレースケール
    edge_img = edge_detect(rect_img)#線画抽出

    image_show(rgb_img)
    image_show(gray_img)
    image_show(edge_img)

#test()
```