mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-15 17:30:27 +08:00
166 lines
5.5 KiB
Python
166 lines
5.5 KiB
Python
import cv2
|
|
import numpy as np
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
|
def convert_color(image, color):
|
|
if color.lower() == 'luv':
|
|
return cv2.cvtColor(image, cv2.COLOR_BGR2Luv)
|
|
elif color.lower() == 'hsv':
|
|
return cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
|
|
elif color.lower() == 'rgb':
|
|
return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
|
else:
|
|
raise RuntimeError("Invalid param `color` in function convert_color")
|
|
|
|
|
|
def calc_mask_from_ranges(image, mask_ranges, color=None, mask_close=False):
|
|
image_for_mask = image if color is None else convert_color(image, color)
|
|
|
|
if mask_ranges is None:
|
|
return None
|
|
|
|
mask = None
|
|
for mask_range in mask_ranges:
|
|
l0, l1, l2 = mask_range[0]
|
|
u0, u1, u2 = mask_range[1]
|
|
if mask is not None:
|
|
mask = cv2.bitwise_or(mask, cv2.inRange(image_for_mask, (l0, l1, l2), (u0, u1, u2)))
|
|
else:
|
|
mask = cv2.inRange(image_for_mask, (l0, l1, l2), (u0, u1, u2))
|
|
|
|
if mask_close:
|
|
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
|
|
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
|
|
|
|
return mask
|
|
|
|
|
|
def show_image_mask(image, mask, color, hist_mask=None):
|
|
image_for_hist = convert_color(image, color)
|
|
image_with_mask = cv2.bitwise_and(image, image, mask=mask)
|
|
|
|
fig, axs = plt.subplots(2, 3, figsize=(15, 8))
|
|
|
|
hist_0 = cv2.calcHist([image_for_hist], [0], hist_mask, [256], [0, 256])
|
|
hist_1 = cv2.calcHist([image_for_hist], [1], hist_mask, [256], [0, 256])
|
|
hist_2 = cv2.calcHist([image_for_hist], [2], hist_mask, [256], [0, 256])
|
|
|
|
axs[0, 0].plot(hist_0, color='r')
|
|
axs[0, 0].set_title('Channel 0 Histogram')
|
|
axs[0, 0].set_xlim([0, 256])
|
|
|
|
axs[0, 1].plot(hist_1, color='g')
|
|
axs[0, 1].set_title('Channel 1 Histogram')
|
|
axs[0, 1].set_xlim([0, 256])
|
|
|
|
axs[0, 2].plot(hist_2, color='b')
|
|
axs[0, 2].set_title('Channel 2 Histogram')
|
|
axs[0, 2].set_xlim([0, 256])
|
|
|
|
# 原图
|
|
axs[1, 0].imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
|
|
axs[1, 0].set_title('Original Image')
|
|
axs[1, 0].axis('off')
|
|
|
|
# 掩码后的图像
|
|
axs[1, 1].imshow(cv2.cvtColor(image_with_mask, cv2.COLOR_BGR2RGB))
|
|
axs[1, 1].set_title('Image with Recommand Mask Range')
|
|
axs[1, 1].axis('off')
|
|
|
|
# 显示掩码
|
|
axs[1, 2].imshow(mask, cmap='gray')
|
|
axs[1, 2].set_title('Recommand Impmortant Mask Range')
|
|
axs[1, 2].axis('off')
|
|
|
|
plt.tight_layout()
|
|
plt.show()
|
|
|
|
|
|
def generate_mask_ranges(image, color, base_mask_ranges=None, thresholds=None):
|
|
image_for_mask = convert_color(image, color)
|
|
|
|
if thresholds is None:
|
|
thresholds = [0.6] * 3
|
|
|
|
base_mask = calc_mask_from_ranges(image, base_mask_ranges, color)
|
|
mask_ranges = []
|
|
mask = cv2.inRange(image_for_mask, (0, 0, 0), (0, 0, 0))
|
|
for i, threshold in enumerate(thresholds):
|
|
current_mask = cv2.bitwise_not(mask)
|
|
if base_mask is not None:
|
|
current_mask = cv2.bitwise_and(base_mask, current_mask)
|
|
|
|
hist_0 = cv2.calcHist([image_for_mask], [0], current_mask, [256], [0, 256])
|
|
hist_1 = cv2.calcHist([image_for_mask], [1], current_mask, [256], [0, 256])
|
|
hist_2 = cv2.calcHist([image_for_mask], [2], current_mask, [256], [0, 256])
|
|
|
|
hue_threshold = threshold * hist_0.max()
|
|
sat_threshold = threshold * hist_1.max()
|
|
val_threshold = threshold * hist_2.max()
|
|
|
|
try:
|
|
l0 = int(np.where(hist_0 > hue_threshold)[0][0])
|
|
u0 = int(np.where(hist_0 > hue_threshold)[0][-1])
|
|
l1 = int(np.where(hist_1 > sat_threshold)[0][0])
|
|
u1 = int(np.where(hist_1 > sat_threshold)[0][-1])
|
|
l2 = int(np.where(hist_2 > val_threshold)[0][0])
|
|
u2 = int(np.where(hist_2 > val_threshold)[0][-1])
|
|
except:
|
|
print(f"Failed at #{i}")
|
|
break
|
|
|
|
mask_ranges.append([[l0, l1, l2], [u0, u1, u2]])
|
|
mask = cv2.bitwise_or(mask, cv2.inRange(image_for_mask, (l0, l1, l2), (u0, u1, u2)))
|
|
|
|
print(f'Recommand {color.upper()} Mask Range: {mask_ranges}')
|
|
show_image_mask(image, calc_mask_from_ranges(image, mask_ranges, color), color, base_mask)
|
|
|
|
return mask_ranges
|
|
|
|
|
|
def compare_2_image_with_mask_ranges(image1, image2, mask_ranges, color, mask_close=False):
|
|
image1_for_mask = convert_color(image1, color)
|
|
image2_for_mask = convert_color(image2, color)
|
|
|
|
mask1 = calc_mask_from_ranges(image1_for_mask, mask_ranges, None, mask_close)
|
|
mask2 = calc_mask_from_ranges(image2_for_mask, mask_ranges, None, mask_close)
|
|
|
|
image1_with_mask = cv2.bitwise_and(image1, image1, mask=mask1)
|
|
image2_with_mask = cv2.bitwise_and(image2, image2, mask=mask2)
|
|
|
|
fig, axs = plt.subplots(2, 3, figsize=(15, 8))
|
|
|
|
# 原图
|
|
axs[0, 0].imshow(cv2.cvtColor(image1, cv2.COLOR_BGR2RGB))
|
|
axs[0, 0].set_title('Original Image')
|
|
axs[0, 0].axis('off')
|
|
|
|
# 掩码后的图像
|
|
axs[0, 1].imshow(image1_for_mask)
|
|
axs[0, 1].set_title('Image for Mask')
|
|
axs[0, 1].axis('off')
|
|
|
|
# 显示掩码
|
|
axs[0, 2].imshow(mask1, cmap='gray')
|
|
axs[0, 2].set_title('Recommand Impmortant Mask Range')
|
|
axs[0, 2].axis('off')
|
|
|
|
# 原图
|
|
axs[1, 0].imshow(cv2.cvtColor(image2, cv2.COLOR_BGR2RGB))
|
|
axs[1, 0].set_title('Original Image')
|
|
axs[1, 0].axis('off')
|
|
|
|
# 掩码后的图像
|
|
axs[1, 1].imshow(image2_for_mask)
|
|
axs[1, 1].set_title('Image for Mask')
|
|
axs[1, 1].axis('off')
|
|
|
|
# 显示掩码
|
|
axs[1, 2].imshow(mask2, cmap='gray')
|
|
axs[1, 2].set_title('Recommand Impmortant Mask Range')
|
|
axs[1, 2].axis('off')
|
|
|
|
plt.tight_layout()
|
|
plt.show()
|