給定普通有色影像找到特定區域
`
import os
import time
import cv2
import numpy as np
import math
import datetime
def filter_rectangles(rect_list, min_area_threshold, width_to_height_ratio_thresh=3):
filtered_rectangles = []
for rect in rect_list:
width = rect['width']
height = rect['height']
area = width * height
if area >= min_area_threshold:
if width / height <= width_to_height_ratio_thresh:
filtered_rectangles.append(rect)
return filtered_rectangles
def merge_intersecting_rectangles(rect_info_list, merge_thresh=20):
rectangles = []
for rect_info in rect_info_list:
x = rect_info['x']
y = rect_info['y']
width = rect_info['width']
height = rect_info['height']
rectangles.append((x, y, width, height))
merged_rectangles = []
for rect in rectangles:
x, y, width, height = rect
rect_cv = (x, y, width, height)
if merged_rectangles:
merge_attempted = False
for i, merged_rect in enumerate(merged_rectangles):
x_intersect = max(rect_cv[0], merged_rect[0])
y_intersect = max(rect_cv[1], merged_rect[1])
x2_intersect = min(rect_cv[0] + rect_cv[2], merged_rect[0] + merged_rect[2])
y2_intersect = min(rect_cv[1] + rect_cv[3], merged_rect[1] + merged_rect[3])
if x_intersect < x2_intersect and y_intersect < y2_intersect:
intersection_area = (x2_intersect - x_intersect) * (y2_intersect - y_intersect)
rect1_area = rect_cv[2] * rect_cv[3]
rect2_area = merged_rect[2] * merged_rect[3]
union_area = rect1_area + rect2_area - intersection_area
iou = intersection_area / union_area
if iou > 0.0:
x = min(rect_cv[0], merged_rect[0])
y = min(rect_cv[1], merged_rect[1])
w = max(rect_cv[0] + rect_cv[2], merged_rect[0] + merged_rect[2]) - x
h = max(rect_cv[1] + rect_cv[3], merged_rect[1] + merged_rect[3]) - y
merged_rectangles[i] = (x, y, w, h)
merge_attempted = True
break
elif (abs(rect_cv[0] - merged_rect[0]) < merge_thresh and
abs(rect_cv[1] - merged_rect[1]) < merge_thresh):
x = min(rect_cv[0], merged_rect[0])
y = min(rect_cv[1], merged_rect[1])
w = max(rect_cv[0] + rect_cv[2], merged_rect[0] + merged_rect[2]) - x
h = max(rect_cv[1] + rect_cv[3], merged_rect[1] + merged_rect[3]) - y
merged_rectangles[i] = (x, y, w, h)
merge_attempted = True
break
if not merge_attempted:
merged_rectangles.append(rect_cv)
else:
merged_rectangles.append(rect_cv)
merged_rect_info_list = [{'x': r[0], 'y': r[1], 'width': r[2], 'height': r[3]} for r in merged_rectangles]
return merged_rect_info_list
def merge_close_rectangles_by_linbian(rect_info_list, merge_thresh=20):
rectangles = []
for rect_info in rect_info_list:
x = rect_info['x']
y = rect_info['y']
width = rect_info['width']
height = rect_info['height']
rectangles.append((x, y, width, height))
merged_rectangles = []
for rect in rectangles:
x, y, width, height = rect
rect_cv = (x, y, width, height)
if merged_rectangles:
merge_attempted = False
for i, merged_rect in enumerate(merged_rectangles):
if abs(rect_cv[1] - (merged_rect[1] + merged_rect[3])) < merge_thresh:
if (rect_cv[0] < merged_rect[0] + merged_rect[2] and
merged_rect[0] < rect_cv[0] + rect_cv[2]):
x = min(rect_cv[0], merged_rect[0])
y = min(rect_cv[1], merged_rect[1])
w = max(rect_cv[0] + rect_cv[2], merged_rect[0] + merged_rect[2]) - x
h = (rect_cv[1] + rect_cv[3]) - merged_rect[1]
merged_rectangles[i] = (x, y, w, h)
merge_attempted = True
break
if not merge_attempted:
merged_rectangles.append(rect_cv)
else:
merged_rectangles.append(rect_cv)
merged_rect_info_list = [{'x': r[0], 'y': r[1], 'width': r[2], 'height': r[3]} for r in merged_rectangles]
return merged_rect_info_list
def hsv_image(img=None, img_path=None,lower_range = np.array([10, 200, 200]),upper_range=np.array([20,255,255])):
if img is not None:
image = img
else:
if img_path == None:
raise Exception("img與img_path引數不能都為None,請傳入引數")
# 讀取影像
image = cv2.imread(img_path)
image = cv2.GaussianBlur(image, (5, 5), 3)
# 將影像轉換為HSV顏色空間
hsv_img = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# 建立掩碼
mask = cv2.inRange(hsv_img, lower_range, upper_range)
#閉運算
kernel=np.ones((3,3),dtype=np.uint8)
mask= closed_image = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
output_mask = mask
return output_mask, image
def exponential_transform(image, gamma=1.5):
try:
# 歸一化影像
img_normalized = image.astype('float32') / 255.0
# 進行指數變換
img_adjusted = 255.0 * (img_normalized ** gamma)
# 逆歸一化還原影像
adjusted_image = np.clip(img_adjusted, 0, 255).astype('uint8')
return adjusted_image
except Exception as e:
print(f"處理影像時出現錯誤:{e}")
return None
def filter_byarea(contours,min_area_threshold=5):
# 根據輪廓面積從大到小排序
contours = sorted(contours, key=cv2.contourArea, reverse=True)
# 過濾掉面積小於閾值的輪廓
filtered_contours = [contour for contour in contours if cv2.contourArea(contour) >= min_area_threshold]
return filtered_contours
def get_contours_bymask(mask):
# 尋找輪廓
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)#cv2.CHAIN_APPROX_NONE
return contours
def get_rect_info(contours) -> list: # 獲取邊與高寬平行的外接矩陣點(不一定是最小外接矩形,最小外接矩形使用cv2.minAreaRect(contour))
rect_info_list = list()
for contour in contours:
# 獲取包圍輪廓的矩形,邊與高寬平行
x, y, w, h = cv2.boundingRect(contour)
# 儲存包圍矩形資訊
rect_info_list.append({
'x': x, # 矩形左上角點的 x 座標。
'y': y, # 矩形左上角點的 y 座標
'width': w,
'height': h
})
return rect_info_list
def draw_rect_by_rect_info_list(rect_info_list, image=None, img_path=None, output_folder=None,name=""):
if image is not None:
image = image
else:
if img_path == None:
raise Exception("img與img_path引數不能都為None,請傳入引數")
# 讀取影像
image = cv2.imread(img_path)
# 建立影像副本,避免修改原始影像
result_image = image.copy()
# 獲取當前時間
# 生成儲存影像的檔名,基於當前時間
current_time = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S-%ms")
# 遍歷矩形資訊列表
for rect_info in rect_info_list:
# 獲取矩形的座標和尺寸資訊
x, y, width, height = rect_info['x'], rect_info['y'], rect_info['width'], rect_info['height']
# 繪製矩形框,綠色
cv2.rectangle(result_image, (x, y), (x + width, y + height), (0, 255, 0), 2)
# 儲存繪製後的輪廓圖
cv2.imwrite(f"./images/result_rect_list2_{current_time}.png", result_image)
return result_image
def filter_rect_info_list_by_wh(rect_info_list,min_w_thresh=5,min__h_thresh=5):
result=[]
for rect_info in rect_info_list:
width=rect_info['width']
height=rect_info['height']
if width= rect2['x'] and
rect1['y'] >= rect2['y'] and
rect1['x'] + rect1['width'] <= rect2['x'] + rect2['width'] and
rect1['y'] + rect1['height'] <= rect2['y'] + rect2['height']):
is_inner = True
break
# 如果沒有其他矩形完全包含當前矩形,則將其加入到過濾後的列表中
if not is_inner:
filtered_rectangles.append(rect1)
return filtered_rectangles
def returnmask(img=None, img_path=None, imshowFlag=False,lower_range=None,upper_range=None): # offset=0微調偏移量,暫時不用
if img is not None:
image = img
else:
if img_path == None:
raise Exception("img與img_path引數不能都為None,請傳入引數")
# 讀取影像
image = cv2.imread(img_path)
# 將影像轉換為HSV顏色空間
hsv_img = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# 建立掩碼
mask = cv2.inRange(hsv_img, lower_range, upper_range)
output_mask=mask
return output_mask, image
def calculate_center(rect): ###找到中心點
x_center = rect['x'] + rect['width'] / 2
y_center = rect['y'] + rect['height'] / 2
return (x_center, y_center)
def distance_between_centers(center1, center2): ####計算兩個中心點的距離
return math.sqrt((center1[0] - center2[0])**2 + (center1[1] - center2[1])**2)
#把相鄰或者相交的框整合成一個大框
def merge_close_rectangles(rect_info_list, max_distance_threshold):
merged_rectangles = []
merged = False
for rect1 in rect_info_list:
rect1_center = calculate_center(rect1)
for i, rect2 in enumerate(merged_rectangles):
rect2_center = calculate_center(rect2)
distance = distance_between_centers(rect1_center, rect2_center)
# print("舊框之間的距離:distance",distance)
if distance < max_distance_threshold:
# Merge rectangles
new_x = min(rect1['x'], rect2['x'])
new_y = min(rect1['y'], rect2['y'])
new_width = max(rect1['x'] + rect1['width'], rect2['x'] + rect2['width']) - new_x
new_height = max(rect1['y'] + rect1['height'], rect2['y'] + rect2['height']) - new_y
merged_rectangles[i] = {'x': new_x, 'y': new_y, 'width': new_width, 'height': new_height}
merged = True
break
if not merged:
merged_rectangles.append(rect1)
merged = False
return merged_rectangles
#透過判定框框離影像邊緣距離的遠近,來看這個框是否保留
def filter_rectangles_by_edge(rectangles, image_width, image_height, edge_threshold):
filtered_rectangles = []
for rect in rectangles:
x_center = rect['x'] + rect['width'] / 2
y_center = rect['y'] + rect['height'] / 2
# Calculate distances to image edges
distance_to_left = x_center
distance_to_right = image_width - x_center
distance_to_top = y_center
distance_to_bottom = image_height - y_center
# Check if any distance is less than the threshold
if (distance_to_left > edge_threshold and
distance_to_right > edge_threshold and
distance_to_top > edge_threshold and
distance_to_bottom > edge_threshold):
filtered_rectangles.append(rect)
return filtered_rectangles
def find_largest_rectangle(rect_info_list, min_area_threshold):
if not rect_info_list:
return None
# 初始化最大矩形的面積和索引
max_area = -1
largest_rect = None
# 遍歷矩形資訊列表,找到面積最大且大於等於最小面積閾值的矩形
for rect in rect_info_list:
x = rect['x']
y = rect['y']
width = rect['width']
height = rect['height']
area = width * height
if area >= min_area_threshold and area > max_area and height > width:
max_area = area
largest_rect = rect
return largest_rect
def return_result(image=None, img_path=None, direction=None):
if image is not None:
image = image
else:
if img_path == None:
raise Exception("img與img_path引數不能都為None,請傳入引數")
# 讀取影像
image = cv2.imread(img_path)
# 獲取影像的寬度和高度
pic_height, pic_width = image.shape[:2]
lower_range=np.array([6, 0, 51])
upper_range=np.array([173, 88, 124])
output_mask, image=returnmask(img=image, img_path=None, imshowFlag=False, lower_range=lower_range, upper_range=upper_range) # 返回一個二值圖和一個原始影像
contours = get_contours_bymask(output_mask)
contours = filter_byarea(contours, min_area_threshold=2) # 過濾掉兩個畫素點之間的小影像,這一步是為了過濾誤檢的小白點
rect_info_list = get_rect_info(contours)
# 定義最小面積閾值
min_area_threshold = 1500
# 呼叫函式找到面積最大且大於等於最小面積閾值的矩形
largest_rectangle = find_largest_rectangle(rect_info_list, min_area_threshold)
if largest_rectangle is not None:
# print("面積最大且大於等於最小面積閾值的矩形資訊:", largest_rectangle)
x = largest_rectangle['x']
y = largest_rectangle['y']
width = largest_rectangle['width']
height = largest_rectangle['height']
if direction ==1:
if 30 < y < 110 and height >= 80:
# print("樣品沒有問題")
result = True
else:
# print("樣品有問題")
result = False
if direction ==2:
if pic_height-110 < y+height < pic_height -30 and height >= 80:
# print("樣品沒有問題")
result = True
else:
# print("樣品有問題")
result = False
else:
# print("輸入列表為空或沒有符合條件的矩形。")
# print("樣品有問題")
result = False
return result
def classify_lingjian(rect_info_list, image_orginal, image, direction=None): #####此時傳入的圖片應該都是高大於寬的型別
if image is not None:
image = image
else:
raise Exception("img引數為None,請傳入引數")
# 獲取列表中元素的數量
num_elements = len(rect_info_list)
# 獲取影像尺寸
pic_height, pic_width = image.shape[:2]
pic_ratio = pic_height / pic_width
maxarea = 0
minarea = 1000000
maxheight = 0
minheight = 1000000
# 根據元素數量執行相關操作
if num_elements == 1:
# print("樣品僅僅只有一個框")
result = False
elif num_elements == 2:
# print("樣品僅僅只有兩個框")
for rect_info in rect_info_list:
rect = rect_info
area1 = rect['width'] * rect['height']
maxarea = max(area1, maxarea)
minarea = min(area1, minarea)
ratio = maxarea/minarea
#暫且先用面積比來進行第一次分類 如果大於3則認為是第一天發的產品,如果小於3,則認為是第二天發的第一個產品
if ratio >= 3 :
result1 = return_result(image=image_orginal, img_path=None, direction=direction)
else:
result1 = False
result = result1
elif num_elements == 3:
for rect_info in rect_info_list:
rect = rect_info
area1 = rect['width'] * rect['height']
height = rect['height']
maxarea = max(area1, maxarea)
minarea = min(area1, minarea)
maxheight = max(height,maxheight)
minheight = min(height,minheight)
ratio = maxarea / minarea
H_ratio = maxheight / minheight
if pic_ratio > 2.14: ##如果圖片寬高比過,大認為僅僅只有三個框就是認為是第二天發的1類圖片
if ratio > 1.5 and H_ratio > 2:
result2 = return_result(image=image_orginal, img_path=None, direction=direction)
else:
result2 = False
else:
result2 = False
result =result2
elif num_elements >= 4:
# print("樣品框框個數大於等於4個框")
if pic_ratio > 2.14: ##如果圖片寬高比過,大認為僅僅只有三個框就是認為是第二天發的1類圖片
# print("樣品執行return_result")
result3 = return_result(image=image_orginal, img_path=None, direction=direction)
else:
# print("樣品區分不出是哪一類")
result3 = False
result =result3
else:
# print("樣品沒有框框")
result = False
return result
def finanl_result(image=None, img_path=None, direction = 0):
if image is not None:
image = image
# 獲取影像尺寸
height, width = image.shape[:2]
# 比較影像的高度和寬度
if height < width:
# 需要順時針旋轉90度
image = cv2.rotate(image, cv2.ROTATE_90_CLOCKWISE)
else:
if img_path == None:
raise Exception("img與img_path引數不能都為None,請傳入引數")
# 讀取影像
image = cv2.imread(img_path)
lower_range = np.array([19, 50, 50])
upper_range = np.array([23, 125, 125])
lower_range1 = np.array([13, 18, 70])
upper_range1 = np.array([24, 89, 164])
mask1 = cv2.inRange(image,lower_range1,upper_range1)
# #
lower_range2 = np.array([11, 6, 56])
upper_range2 = np.array([26, 80, 153])
mask2 = cv2.inRange(image, lower_range2, upper_range2)
#
mask3 = cv2.bitwise_or(mask1,mask2)
image_orignal = image.copy()
image = exponential_transform(image, gamma=1.125)
output_mask, image = hsv_image(img=image, img_path=None, lower_range=lower_range, upper_range=upper_range)
output_mask = cv2.bitwise_or(output_mask,mask3)
contours = get_contours_bymask(output_mask)
contours = filter_byarea(contours, min_area_threshold=20)
rect_info_list1 = get_rect_info(contours)
### 過濾掉極端的框
rect_info_list2 = filter_rect_info_list_by_wh(rect_info_list1, min_w_thresh=10, min__h_thresh=10)
### 呼叫中心點距離合並函式
max_distance_threshold = 35 # Example threshold for maximum distance
rect_info_list = merge_close_rectangles(rect_info_list2, max_distance_threshold) #### 透過距離閾值把幾個重合的框進行合併·
# 呼叫臨邊合併函式
merged_rect_info_list1 = merge_close_rectangles_by_linbian(rect_info_list)
# 呼叫相交合並函式
merged_rect_info_list = merge_intersecting_rectangles(merged_rect_info_list1)
# ## 過濾掉包含的框
rect_info_list3 = filter_inner_rectangles(merged_rect_info_list)
## 利用面積和寬高比過濾掉邊邊角角
# 設定過濾條件
min_area_threshold = 180 # 過濾掉面積小於600的矩形
width_to_height_ratio_thresh = 3.5 # 過濾掉寬度是高度的3倍以上的矩形
filtered_rectangles_1 = filter_rectangles(rect_info_list3, min_area_threshold, width_to_height_ratio_thresh)
### 透過框和圖片邊緣的距離來判斷這個框是否是干擾框,結果返回正常框
filtered_rectangles = filter_rectangles_by_edge(filtered_rectangles_1, image.shape[1], image.shape[0],edge_threshold=25)
# draw_rect_by_rect_info_list(filtered_rectangles, image=image, img_path=None, output_folder="./", name="")
result = classify_lingjian(filtered_rectangles, image_orignal, image, direction)
# print("result", result)
return result
if __name__ == '__main__':
image_path = "./liangpin/jump_cap1_5_1_20240729132711_OK_.png"
image = cv2.imread(image_path,1)
start = time.time()
direction = 1 # 1代表帽子在左邊 2代表帽子在右邊
result = finanl_result(image, direction=direction)
end = time.time()
print("result", result)
# folder_path = r'./loujian' # 沒有誤報
# # 呼叫函式遍歷圖片資料夾
# iamge_path_list = traverse_images(folder_path)
# start = time.time()
# get_result(iamge_path_list)
# end = time.time()`
相關文章
- TPAMI 2024 | 自適應區域特定損失:提高影像分割效能
- Excel2013中如何給特定區域單元格加密?Excel加密
- C# 按鈕影像指定本地資源後提示“未能找到任何適合於指定的區域性或非特定區域性的資源”的解決辦法C#
- Excel如何設定列印區域?Exce列印區域設定教程Excel
- Python剪裁影像中的指定區域Python
- 給定陣列中找到最大的兩個數陣列
- 低光照影像區域級質量推斷
- 領域特定語言筆記筆記
- 影像相似度比較和檢測影像中的特定物
- Python 影像處理 OpenCV (3):影像屬性、影像感興趣 ROI 區域及通道處理PythonOpenCV
- 跨域問題(普通跨域和springsecurity跨域)跨域SpringGse
- 面試題:給定陣列a,找到最大的j-i, 使a[j]>a[i]面試題陣列
- 影像區域性特徵點檢測演算法綜述特徵演算法
- RAC 特定引數設定
- Linux給特定程式單獨指定DNSLinuxDNS
- 找到陣列中出現特定次數數字的問題陣列
- ECharts 根據不同的X軸區域,設定不同區域的背景色Echarts
- win10區域網設定密碼如何設定 win10區域網怎麼設定訪問密碼Win10密碼
- win10怎麼共享給xp_win10與xp區域網共享怎麼設定Win10
- 區域網的組建及設定方法
- 關於sort/hash區域大小的設定
- win10區域網印表機共享設定方法_Win10區域網印表機共享怎麼設定Win10
- Win10區域網共享該怎麼設定?win10系統區域網共享設定的方法Win10
- 微服務不是全部,只是特定領域的子集微服務
- 自動生成特定領域模型和圖表模型
- DSSA特定領域軟體體系結構
- 下載特定區域內街景照片資料 | Download Street View Photos within Selected RegionView
- 跟我學Python影像處理丨獲取影像屬性、興趣ROI區域及通道處理Python
- windows設定僅訪問特定ipWindows
- w10區域網設定怎麼操作_win10建立區域網的步驟Win10
- 區域網共享資料夾設定怎麼弄 區域網檔案共享的辦法
- 開發者需要了解的領域特定語言(DSL)
- oracle給使用者分配特定使用者下特定表的只讀許可權Oracle
- LikeLib:給區塊鏈技術發展換一種思路,也許能找到出路區塊鏈
- php 根據給定字串時間獲取時區PHP字串
- Linux 中如何設定每個特定的時間執行特定的程式Linux
- 手機開發實戰20——GPRS區域定義
- Windows區域網通過NTP設定時間同步Windows