首页 > 其他分享 >给定普通有色图像找到特定区域

给定普通有色图像找到特定区域

时间:2024-08-13 10:27:09浏览次数:12  
标签:info image 有色 height 给定 merged 图像 rectangles rect

`

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<min_w_thresh and height<min__h_thresh:
continue
else:
result.append(rect_info)
return result
def filter_inner_rectangles(rect_info_list): ###合并包围框
filtered_rectangles = []

# 遍历每一个矩形
for rect1 in rect_info_list:
    is_inner = False
    # 检查是否有其他矩形完全包含当前矩形
    for rect2 in rect_info_list:
        if rect1 != rect2:
            if (rect1['x'] >= 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()`

标签:info,image,有色,height,给定,merged,图像,rectangles,rect
From: https://www.cnblogs.com/littlecute555/p/18356362

相关文章

  • Python图像背景去除
    目录......
  • IRAP图像类型
    视频序列里包含不同类型的图像,I帧(只使用帧内预测)、P帧(单向帧间预测)、B帧(双向帧间预测)。由于P帧和B帧在帧间预测时要参考其他帧,所以形成了不同帧间的时域依赖关系(时域预测帧必须在其参考帧解码后才能解码)。 上图展示了不同帧间的时域依赖关系。图上数字是编解码顺序,从左到右是......
  • 使用Mask R-CNN实现图像分割
    使用MaskR-CNN实现分割步骤1.导入依赖项import osimport torchimport numpy as npimport matplotlib.pyplot as pltfrom PIL import Imagefrom torch.utils.data import Dataset, DataLoaderfrom torchvision.transforms import Compose, ToTe......
  • 裁剪图像--原始大小变换
    用QPainter画出图像,画出要取出的矩形位置头文件源码如下:CusImageCrop.h点击查看代码`#pragmaonce#include<QObject>#include<QPaintEvent>#include<QLabel>#include<QMutex>#include<QTimer>#pragmaexecution_character_set("utf-8")class......
  • 基于人工智能的图像物体擦除与背景填充技术
    摘要:本文介绍了一种基于人工智能的图像处理技术,该技术能够自动识别并擦除图像中的指定物体,同时智能填充背景,以实现图像的自然恢复。该技术为用户提供了一种高效、简便的图像编辑工具,适用于多种应用场景。关键词:人工智能,图像编辑,物体擦除,背景填充1.引言在图像编辑领域,去......
  • 图像数据处理1
    一、图像数据的表示与基本运算1.1图像文件的读写与显示1.1.1OpenCV读写与显示图像文件①彩色图像转为灰度图像importcv2ascvimportsysimportos#从当前工作目录下读入一幅彩色图像img_path='E:\PyCharmCommunityEdition2024.1.1\image\slpn.jpg'#此处为绝对......
  • 图像分割算法
    5.1阈值分割(Thresholding)介绍阈值分割是一种简单而有效的图像分割方法,通过设置一个或多个阈值,将图像分割为前景和背景区域。常见的阈值分割方法包括全局阈值、自适应阈值和Otsu阈值。原理阈值分割通过比较像素值与设定的阈值,将像素分类为前景或背景。公式在阈值分割......
  • 电子商务图像生成技术:AI驱动的自动化流程
    摘要:本文介绍了一种基于人工智能技术的电子商务图像生成系统,该系统能够自动化地完成商品图像的生成过程。通过简单的三个步骤,用户可以快速生成高质量的电商主图和头图,从而提高工作效率并降低成本。**关键词:**人工智能,电商图像,自动化生成,图像处理1.引言在电子商务领域,高质......
  • AI在医学领域:nnSynergyNet3D高精度分割肝硬化肝脏体MRI图像
    关键词:肝硬化肝脏分割、协同深度学习模型、跨模态泛化    肝硬化是慢性肝病(CLD)的最后阶段,是一个重大的全球性健康问题。2019年,它是全球死亡原因的第11位,占全球死亡人数的2.4%。尽管病毒性肝炎仍然是终末期肝病的主要原因,但与代谢功能障碍相关的脂肪肝病(MASLD)预计将由于......
  • 利用OpenCvSharp进行图像相关操作
    前言程序设计过程,有时也需要对图像进行一些简单操作,C#没有现成的图像处理库,但有人对OpenCV进行了包装,我们可以很方便的使用OpenCvSharp对图像进行操作。当然了,这也需要使用的人员进行一些研究,但相对于C++版本,它已经非常友好了。1、显示图像代码:privatevoidbutton1_Click(......