app / diff.py
kikuepi's picture
Upload 5 files
e73c0a8 verified
import streamlit as st
from PIL import Image
import cv2
import numpy as np
def diff(image_file1, image_file2):
TYPE = st.sidebar.selectbox("可視化手法の選択", ["矩形", "点群"])
if (TYPE == "矩形"):
rectangle_diff(image_file1, image_file2)
elif (TYPE == "点群"):
point_diff(image_file1, image_file2)
def point_diff(image_file1, image_file2):
image1 = Image.open(image_file1)
image2 = Image.open(image_file2)
col1, col2 = st.columns(2)
diff_Thresholds = st.sidebar.slider("差分の閾値処理", 10, 255, 50)
with col1:
st.image(image1, caption='1枚目の画像', use_column_width=True)
with col2:
st.image(image2, caption='2枚目の画像', use_column_width=True)
image1_cv = cv2.cvtColor(np.array(image1), cv2.COLOR_RGB2BGR)
image2_cv = cv2.cvtColor(np.array(image2), cv2.COLOR_RGB2BGR)
gray1 = cv2.cvtColor(image1_cv, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(image2_cv, cv2.COLOR_BGR2GRAY)
sift = cv2.SIFT_create()
keypoints1, descriptors1 = sift.detectAndCompute(gray1, None)
keypoints2, descriptors2 = sift.detectAndCompute(gray2, None)
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(descriptors1, descriptors2, k=2)
good_matches = []
for m, n in matches:
if m.distance < 0.8 * n.distance:
good_matches.append(m)
if len(good_matches) > 4:
src_pts = np.float32([keypoints1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)
dst_pts = np.float32([keypoints2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)
H, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
height, width, channels = image2_cv.shape
transformed_img = cv2.warpPerspective(image1_cv, H, (width, height))
transformed_gray = cv2.cvtColor(transformed_img, cv2.COLOR_BGR2GRAY)
img_diff = cv2.absdiff(transformed_gray, gray2)
_, img_th = cv2.threshold(img_diff, diff_Thresholds, 255, cv2.THRESH_BINARY)
kernel = np.ones((3, 3), np.uint8)
img_th = cv2.morphologyEx(img_th, cv2.MORPH_OPEN, kernel, iterations=2)
img_th = cv2.dilate(img_th, kernel, iterations=1)
points = np.column_stack(np.where(img_th > 0.00000001))
for point in points:
cv2.circle(transformed_img, (point[1], point[0]), 2, (0, 0, 255), -1)
st.image(cv2.cvtColor(transformed_img, cv2.COLOR_BGR2RGB), caption='変換後の画像と差異', use_column_width=True)
def merge(rectangles, image_area, dist_threshold=10, diff_rate=0.5): #矩形の計算
merged_rec = []
used = [False] * len(rectangles)
for i, rect1 in enumerate(rectangles):
if used[i]:
continue
x1, y1, w1, h1 = rect1
area1 = w1 * h1
merged = False
for j, rect2 in enumerate(rectangles):
if i == j or used[j]:
continue
x2, y2, w2, h2 = rect2
area2 = w2 * h2
center1 = np.array([x1 + w1 / 2, y1 + h1 / 2])
center2 = np.array([x2 + w2 / 2, y2 + h2 / 2])
distance = np.linalg.norm(center1 - center2)
if distance < dist_threshold and abs(area1 - area2) < diff_rate * max(area1, area2):
new_x = min(x1, x2)
new_y = min(y1, y2)
new_w = max(x1 + w1, x2 + w2) - new_x
new_h = max(y1 + h1, y2 + h2) - new_y
merged_rec.append((new_x, new_y, new_w, new_h))
used[i] = used[j] = True
merged = True
break
if not merged:
merged_rec.append(rect1)
filter_rect = []
for rect in merged_rec:
x, y, w, h = rect
area = w * h
ok = True
if area >= (1/3) * image_area:
ok = False
for other_rect in merged_rec:
if rect == other_rect:
continue
ox, oy, ow, oh = other_rect
other_area = ow * oh
if area < other_area and abs(area - other_area) > diff_rate * max(area, other_area):
ok = False
break
if ok:
filter_rect.append(rect)
return filter_rect
def rectangle_diff(image_file1, image_file2):
image1 = Image.open(image_file1)
image2 = Image.open(image_file2)
col1, col2 = st.columns(2)
diff_Thresholds = st.sidebar.slider("差分の閾値処理", 10, 255, 50)
distance_threshold = st.sidebar.slider("矩形の結合距離", 1, 50, 10)
size_difference_ratio = st.sidebar.slider("サイズ差異の割合", 0.0, 1.0, 0.5)
with col1:
st.image(image1, caption='1枚目の画像', use_column_width=True)
with col2:
st.image(image2, caption='2枚目の画像', use_column_width=True)
image1_cv = cv2.cvtColor(np.array(image1), cv2.COLOR_RGB2BGR)
image2_cv = cv2.cvtColor(np.array(image2), cv2.COLOR_RGB2BGR)
gray1 = cv2.cvtColor(image1_cv, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(image2_cv, cv2.COLOR_BGR2GRAY)
sift = cv2.SIFT_create()
keypoints1, descriptors1 = sift.detectAndCompute(gray1, None)
keypoints2, descriptors2 = sift.detectAndCompute(gray2, None)
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(descriptors1, descriptors2, k=2)
good_matches = []
for m, n in matches:
if m.distance < 0.8 * n.distance:
good_matches.append(m)
if len(good_matches) > 4:
src_pts = np.float32([keypoints1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)
dst_pts = np.float32([keypoints2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)
H, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
height, width, channels = image2_cv.shape
transformed_img = cv2.warpPerspective(image1_cv, H, (width, height))
transformed_gray = cv2.cvtColor(transformed_img, cv2.COLOR_BGR2GRAY)
img_diff = cv2.absdiff(transformed_gray, gray2)
_, img_th = cv2.threshold(img_diff, diff_Thresholds, 255, cv2.THRESH_BINARY)
kernel = np.ones((3, 3), np.uint8)
img_th = cv2.morphologyEx(img_th, cv2.MORPH_OPEN, kernel, iterations=2)
img_th = cv2.dilate(img_th, kernel, iterations=1)
contours, _ = cv2.findContours(img_th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
rectangles = [cv2.boundingRect(contour) for contour in contours]
image_area = height * width
filtered_rectangles = merge(rectangles, image_area, distance_threshold, size_difference_ratio)
for x, y, w, h in filtered_rectangles:
cv2.rectangle(transformed_img, (x, y), (x + w, y + h), (0, 0, 255), 2)
st.image(cv2.cvtColor(transformed_img, cv2.COLOR_BGR2RGB), caption='変換後の画像と差異', use_column_width=True)