์ด๋ฒ 4์ ๋ง์ ์๋ธ๋ฆฌํ์ ๊ฒ์ํ ๋ณด๋ฉด์ ์๊ฐ ์ข ๋ณด๋ด๊ณ ์์๋๋ฐ ํ์ด์ฌ์ผ๋ก ์ด๋ฏธ์ง๋ค์ ๋ถ์ด๊ณ ์ด๋ฏธ์ง๋ก ๊ทธ๋ํ๋ฅผ ๋ง๋๋ ์์ ์ ํ ์ฌ๋์ ์ฐพ๋๋ค๋ ๊ธ์ ๋ดค๋ค. ๊ทธ๋์ ๊ทธ๋ฅ ์ธํ์ผ๋ก ๋ค์ด์ค๋ ์ด๋ฏธ์ง ํ ๋, ์ธ ๊ฐ ์ ๋ ์๋์ผ๋ก ๊ฐ๋ก๋ก ์ฐ๊ฒฐํ๋ ๊ฐ๋จํ ํ๋ก๊ทธ๋จ์ด๊ฒ ๊ฑฐ๋ ํ๊ณ ์ฐ๋ฝํ๋ค. ๊ทธ๋ฐ๋ฐ ์๊ณ ๋ณด๋ Open-CV๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ๋ฌ ์ด๋ฏธ์ง์ ๊ณตํต ๋ถ๋ถ์ ์ฐพ์์ ์ฐ๊ฒฐํ์ฌ ํฐ ์ต์ข ์ด๋ฏธ์ง๋ฅผ ๋ง๋๋ ํ๋ก์ ํธ์๋ค.
์ซ ๊น๋ค๋ก์ ๋ณด์ฌ์ ํ์ง ๋ง๊น ํ๋๋ฐ, ์น๊ตฌ๊ฐ OpenCV์ ImageStitcher ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ผ๋๊ฒ ์๋ค๊ณ ํด์ ์ฌ์ฉํด๋ณด๋ ์ฝ๋ ๋ช ์ค์ด๋ฉด ๊ธ๋ฐฉ ์์ฑ ๋๋ค. ๋ฏธ์ธํ ๊ฐ๋ค์ ์ข ํ ์คํธํ๋ฉด์ ๋ง์ถฐ๊ฐ๋ฉด ๊ธ๋ฐฉ ํ ๊ฒ ๊ฐ๋ค๊ณ ์๊ฐํด์ ์๋ฝํ๋ค. (๊ทธ๋ ๊ฒ ๊ณ ๋์ ์์...)
์ด ํ๋ก์ ํธ๋ ํ๊ฒฝ๊ณตํ๊ณผ ๋ํ์์์ ์งํํ๋ ์ฐ๊ตฌ์ด๋ค. ์ด ์ฐ๊ตฌ์ ๋ชฉํ๋ "๊ณต์ค์์ ๋๋ก ์ผ๋ก ์ฐ์ ํธ์ ์ด๋ฏธ์ง๋ฅผ ์ธํ์ผ๋ก ์์ ๊ฐ์ ํ๋ณํ์ฌ ๋ น์กฐ์ ์์น ๋ฐ ์ ๋๋ฅผ ํ์ ํ์ฌ ๊ทธ๋ํ๋ก ํํํ๋ ๊ฒ"์ด๋ค. ์ด ํ๋ก์ ํธ์์ ๋ด๊ฐ ํ๋ก๊ทธ๋๋ฐ์ ์ผ๋ก ๋งก์ ๋ถ๋ถ์ ํฌ๊ฒ Image Stitching๊ณผ Graph Making์ ๋ ํํธ๋ก ๋๋ ์ ์๊ฒ ๋ค.
์ฌ๋ฌ ์ด๋ฏธ์ง์ ๊ณตํต ๋ถ๋ถ์ ์ฐพ์์ ํ๋์ ํฐ ์ด๋ฏธ์ง๋ก ํฉ์น๋ค.
์ด๋ฏธ์ง ๋ก๋
๋ก๋ฉ : ์์ ๋์ ์ค๋น๋ฌผ์ ์ฌ๋ฆฌ๋ ์์
์ด๋ฏธ์ง ์ฉ๋์ด ํฌ๋ฉด? ์์ ์ด ์ค๋ ๊ฑธ๋ฆฌ๊ฑฐ๋ ํ ์์ ๋์์ ํ ๋ฒ์ ์ฒ๋ฆฌ ๋ชป ํ ์๋ ์์
์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ฆ : ๊ทธ๋ด ๊ฒฝ์ฐ์ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์ค์ฌ์ ๋น ๋ฅด๊ณ ๋ง์ ์์ ํ ๋ฒ์ ์ฒ๋ฆฌ
Image Stitching
์ด๋ฏธ์ง ์คํฐ์นญ : ์ฌ๋ฌ ์ด๋ฏธ์ง์์ ๊ณตํต ๋ถ๋ถ์ ์ฐพ์์ ์ฐ๊ฒฐํ๋ ๊ฒ
๊ณตํต ๋ถ๋ถ(match point)์ฐพ๊ธฐ : ๋ ์ด๋ฏธ์ง์์ ๊ณตํต ๋ถ๋ถ์ ์ฐพ๋๋ค.
๊ณตํต ๋ถ๋ถ ์ฐ๊ฒฐ : ์ฌ๋ฌ ์ด๋ฏธ์ง์์ ๊ณตํต ๋ถ๋ถ์ ์ฐพ์์ 2D ๋ณํ ํ ์ฐ๊ฒฐํ๋ ๊ฒ
2D ๋ณํ : ํ๋ฉด์์ ๋ํ์ ์ฌ๋ฌ๊ฐ์ง ๋ณํ
2D ๋ณํ์ด ํ์ํ ์ด์ : ๊ฐ์ ์ด๋ฏธ์ง๋ผ๋ ์์น๋ ๊ฐ๋์ ๋ฐ๋ผ ๋ค๋ฅด๊ฒ ๋ณด์ด๊ธฐ ๋๋ฌธ์ ์ด๋ฅผ ๊ต์ ํ๊ธฐ ์ํด์
๋ชจ๋ ์ด๋ฏธ์ง์ ๋ํด ๋ฐ๋ณต
ํ์ ๋ชจ๋ ์ํฌํธ
"""\
image_stitching.py
module import part
"""
import os
import math
from PIL import Image
from imutils import paths
import numpy as np
import argparse
import imutils
import cv2
์ด๋ฏธ์ง ๋ฆฌ์ฌ์ด์ฆ
"""\
image_stitching.py
function resize
ํ์ผ ์ด๋ฆ์ ๋ฐ์์ ์ด๊ณ ์ด๋ฏธ์ง์ ํฌ๊ธฐ๊ฐ 1MB๋ณด๋ค ํฌ๋ฉด
ํฌ๊ธฐ๋ฅผ ์ ์ ์ค์ฌ๋๊ฐ์ 1MB๋ณด๋ค ์๊ฒ ๋๋ฉด ํด๋น ์ด๋ฏธ์ง๋ฅผ ๋ฆฌํดํ๋ ํจ์
์ฒ์๋ถํฐ 1MB๋ณด๋ค ์๋ค๋ฉด ๊ทธ๋๋ก ๋ฆฌํด
"""
def resize(filename):
img = cv2.imread(filename)
width, height = img.shape[:2]
if height * width * 3 <= 2 ** 25:
return img
i = 2
t_height, t_width = height, width
while t_height * t_width * 3 > 2 ** 25:
t_height = int(t_height / math.sqrt(i))
t_width = int(t_width / math.sqrt(i))
i += 1
height, width = t_height, t_width
image = Image.open(filename)
resize_image = image.resize((height, width))
filename = filename[:-1 * (len(filename.split(".")[-1]) + 1)] + "_resized." + filename.split(".")[-1]
resize_image.save(filename)
img = cv2.imread(filename)
os.system("del " + filename.replace("/", "\\"))
return img
์ ๋ ฅ ๊ฐ ์ฒ๋ฆฌ
"""\
image_stitching.py
argument parsing
-i ์
๋ ฅ ์ด๋ฏธ์ง๋ค์ ํด๋ ๋๋ ํ ๋ฆฌ
-o ์ถ๋ ฅํ ๊ฒฐ๊ณผ ์ด๋ฏธ์ง์ ํ์ผ ์ด๋ฆ
"""
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--images", type=str, required=True,
help="path to input directory of images to stitch")
ap.add_argument("-o", "--output", type=str, required=True,
help="path to the output image")
args = vars(ap.parse_args())
์ด๋ฏธ์ง ๋ก๋ฉ
"""\
image_stitching.py
loading images
์
๋ ฅ ๋ฐ์ ํด๋์ ๋ชจ๋ ํ์ผ๋ค์ ๋ฆฌ์ฌ์ด์ฆ ์ํค๊ณ ๋ฆฌ์คํธ์ ๋ก๋ํ๋ ๋ถ๋ถ
"""
print("[INFO] loading images...")
imagePaths = sorted(list(paths.list_images(args["images"])))
images = []
for imagePath in imagePaths:
image = resize(imagePath)
images.append(image)
Image Stitching
"""\
image_stitching.py
image stitching
์ด๋ฏธ์ง ์คํฐ์นญํ์ฌ ์ฑ๊ณต ์ฌ๋ถ(status)์ ๊ฒฐ๊ณผ(stitched)๋ฅผ ๋ฐ๋ ๋ถ๋ถ
"""
print("[INFO] stitching images...")
stitcher = cv2.createStitcher() if imutils.is_cv3() else cv2.Stitcher_create()
(status, stitched) = stitcher.stitch(images)
๊ฒฐ๊ณผ ์ ์ฅ ๋ฐ ์์ธ ์ฒ๋ฆฌ
"""\
image_stitching.py
exception handling
status๊ฐ 0์ธ ๊ฒฝ์ฐ(stitching ์ฑ๊ณต) ์ด๋ฏธ์ง๋ฅผ ์๊น ๋ฐ์ ์ด๋ฆ์ผ๋ก ์ ์ฅํ๊ณ ๋ณด์ฌ์ค๋ค.
status๊ฐ 0์ด ์๋ ๊ฒฝ์ฐ(stitching ์คํจ ์์ธ)์ ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํ๋ค.
1 : ์ด๋ฏธ์ง๋ฅผ ์ฐ๊ฒฐ ์ํค๊ธฐ์ match point๊ฐ ๋ถ์กฑํด์ ๋์ค๋ ์๋ฌ, ์ด๋ฏธ์ง๋ฅผ ๋ ์ถ๊ฐ์์ผ์ค์ผ ํ๋ค.
2 : 2D ์ด๋ฏธ์ง ๋ณํ์ ํ์ง ๋ชปํ๋ ์๋ฌ, ์ด๋ฏธ์ง๋ฅผ ๋ค์ ์ฐ๋ ๊ฒ์ ์ถ์ฒํ๋ค.
3 : ์นด๋ฉ๋ผ ์์น์ ์๋ฌ, ์นด๋ฉ๋ผ์ ๋ฐฉํฅ์ด ์๋ชป๋ผ์ ๋์ค๋ ์๋ฌ, ์
๋ ฅ ์ด๋ฏธ์ง๋ค์ ๊ฐ์ ๋ฐฉํฅ์ผ๋ก ํ์ ์ํค๊ฑฐ๋ ์๋ก์ด ์ด๋ฏธ์ง๋ฅผ ์ฐ์ด์ผ ํ๋ค.
"""
if status == 0:
# write the output stitched image to disk
cv2.imwrite(args["output"], stitched)
# display the output stitched image to our screen
cv2.imshow("Stitched", stitched)
cv2.waitKey(0)
else:
if status == cv2.STITCHER_ERR_NEED_MORE_IMGS:
print("[INFO] image stitching failed (1: STITCHER_ERR_NEED_MORE_IMGS)")
elif status == cv2.STITCHER_ERR_HOMOGRAPHY_EST_FAIL:
print("[INFO] image stitching failed (2: STITCHER_ERR_HOMOGRAPHY_EST_FAIL)")
else:
print("[INFO] image stitching failed (3: STITCHER_ERR_CAMERA_PARAMETERS_ADJUSTMENT_FAIL)")
์ ๋ ฅ ์ด๋ฏธ์ง
๊ฒฐ๊ณผ ์ด๋ฏธ์ง
์์ ๊ฐ์ด ๊ฒน์น๋ ๋ถ๋ถ๋ ๋ง๊ณ ๋งค์นญ ํฌ์ธํธ๊ฐ ๋ช ํํ ์ด๋ฏธ์ง๋ ์ฌ์ด๋ฐ ๊ฒฐ๊ณผ๊ฐ ์ ์ ๋์ค๋ ์ด๋ฏธ์ง๋ ๋ง์๋ค.
์ด๋ฏธ์ง์ HSV ์์ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ น์กฐ ์์น์ ์ ๋๋ฅผ ๋ํ๋ด๋ ๊ทธ๋ํ๋ฅผ ๋ง๋ ๋ค.
HSV ๊ฐ ์ถ์ถ
HSV
OpenCv์ BGR2HSV ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฐ๋ฉด ๋จ
๋ น์กฐ ๋ ๋ฒจ ๊ณ์ฐ
ํด๋ผ์ด์ธํธ์์ ์ค ๋ น์กฐ ๊ณ์ฐ ๋ฐฉ๋ฒ์ ๊ฐ๊ณ ๋ น์กฐ ๋ ๋ฒจ์ 0๋ถํฐ 3์ผ๋ก ๊ตฌ๋ถํ๋ ํจ์๋ฅผ ๋ง๋ค์๋ค.
def set_range(h, s, v):
if 72 >= h >= 66 and 91 >= s >= 59 and 255 >= v >= 66:
return 3
elif 75 >= h >= 73 and 234 >= s >= 31 and 118 >= v >= 0:
return 2
elif 134 >= h >= 35 and 59 >= s >= 0 and 100 >= v >= 73:
return 1
return 0
๊ณ์ฐ๋ ๊ฐ์ผ๋ก ๊ทธ๋ํ ๋ง๋ค๊ธฐ
ํ์ ๋ชจ๋ ์ํฌํธ
"""\
graph_maker.py
ํ์ํ ๋ชจ๋ ์ํฌํธ
"""
import argparse
import os
import cv2
import math
import numpy as np
import pandas as pd
import plotly.graph_objects as go
import plotly
from PIL import Image
๋ น์กฐ ๋ ๋ฒจ ๊ณ์ฐ ํจ์
"""\
graph_maker.py
HSV ๋ฐ์ดํฐ๋ก ๋
น์กฐ ๋ ๋ฒจ ๊ณ์ฐํ๋ ํจ์
"""
def set_range(h, s, v):
if 72 >= h >= 66 and 91 >= s >= 59 and 255 >= v >= 66:
return 3
elif 75 >= h >= 73 and 234 >= s >= 31 and 118 >= v >= 0:
return 2
elif 134 >= h >= 35 and 59 >= s >= 0 and 100 >= v >= 73:
return 1
return 0
๊ทธ๋ํ์ ์๊ฒฝ๋ ๊ฐ ๊ณ์ฐ
"""\
graph_maker.py
์๊ฒฝ๋๋ฅผ ๊ทธ๋ํ์ x, y์ถ์ ํ๊ธฐํ๊ธฐ ์ํด ์๊ฒฝ๋ ๊ฐ์ ์ด๋ฏธ์ง์ ๋๋น/๋์ด์ ํฝ์
๊ฐ์๋งํผ์ผ๋ก ๋๋ ์ ๋ฆฌ์คํธ๋ก ๋ฆฌํดํ๋ ํจ์
ํ์ด์ฌ range๋ก๋ float ํ์
๋ฐ์ดํฐ๋ฅผ ๋๋์ง ๋ชป ํ๋ฏ๋ก ๋ฐ๋ก ์ ์
"""
def float_range(start, end, cnt):
list = []
step = (end - start) / (cnt - 1)
for i in range(cnt):
list.append(start + i * step)
return list
์ ๋ ฅ๊ฐ ์ฒ๋ฆฌ
"""\
graph_maker.py
argument parsing
-i ๊ทธ๋ํ๋ก ๋ง๋ค ์ด๋ฏธ์ง ํ์ผ ์ด๋ฆ
-o ์ถ๋ ฅ์ผ๋ก ์ ์ฅํ ์ด๋ฏธ์ง ํ์ผ ์ด๋ฆ
-lat1 ์๋์ ์์ ๊ฐ
-lat2 ์๋์ ๋ ๊ฐ
-lon1 ๊ฒฝ๋์ ์์ ๊ฐ
-lon2 ๊ฒฝ๋์ ๋ ๊ฐ
lat1๊ณผ lat2๋ ๋ ๋ค ์๊ฑฐ๋ ๋ ๋ค ์๊ฑฐ๋ ํด์ผํจ
lon1๊ณผ lon2๋ ๋ ๋ค ์๊ฑฐ๋ ๋ ๋ค ์๊ฑฐ๋ ํด์ผํจ
"""
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", type=str, required=True,
help="path to input file name of images to stitch")
ap.add_argument("-o", "--output", type=str, required=True,
help="path to the output image")
ap.add_argument("-lat1", "--latitude1", type=float, required=False,
help="image's start latitude")
ap.add_argument("-lat2", "--latitude2", type=float, required=False,
help="image's end latitude")
ap.add_argument("-lon1", "--longitude1", type=float, required=False,
help="image's start longitude")
ap.add_argument("-lon2", "--longitude2", type=float, required=False,
help="image's end longitude")
args = vars(ap.parse_args())
์ด๋ฏธ์ง ๋ก๋ฉ
"""\
graph_maker.py
์ด๋ฏธ์ง๊ฐ 1MB๋ณด๋ค ํฌ๋ฉด ์ค์ด๊ณ ์์ผ๋ฉด ๊ทธ๋๋ก ๋ก๋ํ๋ ๋ถ๋ถ
"""
print("Image loading start")
print("Image resizing start")
img_color = resize(filename)
height, width = img_color.shape[:2]
print("Image resizing end")
print("Image loading end")
HSV ๊ฐ ์ถ์ถ
"""\
graph_maker.py
์ด๋ฏธ์ง๋ฅผ ๋ก๋ํ๋ฉด ์ฒ์์ ๊ฐ ํฝ์
์ BGR(RGB)๊ฐ์ ๊ฐ์ง๋ numpy array๋ก ์ ์ฅ๋์ด ์๋ค.
์ด๋ฏธ์ง๋ฅผ HSVํ์์ผ๋ก ๋ณํ์ํค๊ณ H, S, V ๊ฐ์ ๊ฐ๊ฐ column์ผ๋ก ๊ฐ์ง๋ pandas DataFrame์ผ๋ก ๋ณํ ์ํจ๋ค.
"""
img_hsv = cv2.cvtColor(img_color, cv2.COLOR_BGR2HSV)
print("Extracting HSV data start")
data = pd.DataFrame(np.concatenate(img_hsv))
print("Extracting HSV data end")
data.columns = ["H", "S", "V"]
๋ น์กฐ ๋ ๋ฒจ ๊ณ์ฐ
"""\
graph_maker.py
DataFrame์ผ๋ก ๋ณํ์ํจ ๋ฐ์ดํฐ๋ฅผ applyํจ์(๊ฐ ์ธ๋ฑ์ค์ ์
๋ ฅ ๋ฐ๋ ํจ์๋ฅผ ์ ์ฉ)๋ฅผ ์ฌ์ฉํ์ฌ ์๊น ๋ง๋ set_range()๋ฅผ ๋ชจ๋ ํฝ์
์ ์ ์ฉ์ํจ๋ค.
๊ทธ๋ฌ๊ณ ์ถ๋ ฅํด๋ณด๋ ์ด๋ฏธ์ง์ ๊ทธ๋ํ๊ฐ ๊ฑฐ๊พธ๋ก ๋์ค๋ ๊ฒ์ ํ์ธํด์ ๋ค์ง์ด์คฌ๋ค.(flip())
"""
print("Calculating \"Range\" data start")
data["Range"] = data.apply(lambda x: set_range(x['H'], x['S'], x['V']), axis=1)
data["Range"] = np.flip(data["Range"])
print("Calculating \"Range\" data end")
๋ น์กฐ ๋ ๋ฒจ ๋ฐ์ดํฐ๋ฅผ ์ด๋ฏธ์ง ๋ชจ์์ผ๋ก ๋ง๋ค๊ธฐ
"""\
graph_maker.py
ํ์ฌ๋ column ํ๋์ง๋ฆฌ DataFrame์ผ๋ก ๋์ด ์์ผ๋ฏ๋ก ๊ทธ๋ํ๋ก ๋ง๋ค๊ธฐ ์ํด ๋์ด * ๋๋น ํฌ๊ธฐ์ DataFrame์ผ๋ก ๋ง๋ค์ด ์ค๋ค.
๊ทธ๋ฆฌ๊ณ ์๊น ์๋๋ ๊ฒฝ๋๋ฅผ ๋ฐ์์ผ๋ฉด x, y์ถ์ ๋งคํํด์ค๋ค.
"""
y = np.array(data['Range'])
z_data = pd.DataFrame(y.reshape(height, width)) # Size variations according to pixel
if args['longitude1']:
z_data.index = float_range(args['longitude1'], args['longitude2'], height)
if args['latitude1']:
z_data.columns = float_range(args['latitude1'], args['latitude2'], width)
HeatMap ๋ง๋ค๊ธฐ
"""\
graph_maker.py
plotly์ graph object๋ฅผ ์ฌ์ฉํ์ฌ HeatMap์ ๋ง๋ ๋ค
์์์ ํด๋ผ์ด์ธํธ์์ ์ค ์ปค์คํ
์์์ผ๋ก ํ๊ณ ํ์ดํ๊ณผ ๋ง์ง์ ์ค๋ค.
"""
fig_heatmap = go.Figure(data=go.Heatmap(z=z_data,
connectgaps=True,
colorscale=[[0.0, "rgb(0,8,135)"],
[1.0, "rgb(0,135,8)"]]))
fig_heatmap.update_layout(title='HSV Graph', autosize=True,
margin=dict(l=65, r=50, b=65, t=90))
3D ๊ทธ๋ํ ๋ง๋ค๊ธฐ
"""\
graph_maker.py
plotly์ graph object๋ฅผ ์ฌ์ฉํ์ฌ 3D Graph๋ฅผ ๋ง๋ ๋ค
์์์ ํด๋ผ์ด์ธํธ์์ ์ค ์ปค์คํ
์์์ผ๋ก ํ๊ณ ํ์ดํ๊ณผ ๋ง์ง์ ์ค๋ค.
"""
fig_3d = go.Figure(data=[go.Surface(z=z_data.values,
colorscale=[[0.0, "rgb(0,8,135)"],
[1.0, "rgb(0,135,8)"]])])
fig_3d.update_layout(title='HSV Graph', autosize=True,
scene_camera_eye=dict(x=1.87, y=0.88, z=-0.64),
margin=dict(l=65, r=50, b=65, t=90))
์ด๋ฏธ์ง ์ ์ฅ ํ ํ์
"""\
graph_maker.py
์คํ ์์ ์
๋ ฅ ๋ฐ์ ์ด๋ฆ์ ๊ฐ๊ฐ Heatmap๊ณผ 3D_graph ์ด๋ฆ์ ๋ถ์ฌ์ ์ด๋ฏธ์ง๋ก ์ ์ฅํ๊ณ
์น ๋ธ๋ผ์ฐ์ ๋ก ์ธํฐ๋ ํฐ๋ธํ js ๊ทธ๋ํ๋ฅผ ๋์ด์ค๋ค.
"""
output = args['output']
if '.' in args['output']:
output = args['output'][:-1 * (len(args['output'].split(".")[-1]) + 1)]
else:
args['output'] = output + ".png"
plotly.io.write_image(fig_heatmap, output + "_heatmap." + args['output'].split(".")[-1])
plotly.io.write_image(fig_3d, output + "_3D_graph." + args['output'].split(".")[-1])
fig_heatmap.show()
fig_3d.show()
์ ๋ ฅ ์ด๋ฏธ์ง
๊ฒฐ๊ณผ ๊ทธ๋ํ
HeatMap
3D Graph