使用yolo识别模型对比两张图片并标记不同

目录

需求:

难点:

思路:

代码:

1、stage1.py

结果:

2、stage2.py

结果:

3、stage3.py

结果:

总结:


需求:

无人机视角下,不同时间同一地点拍摄的两张图片,比对后,将不同标注在第一张图片上,比如说违建,第一次拍摄的时候发现有违建,过段时间需要检查这个违建拆除了没有于是再拍摄一张,开发者要做的是,比对两张图片的违建情况并标记出来

难点:

两张图片拍摄角度不完全一样、图片大小可能存在差异、图片上除了违建不同之外可能存在其他不同(比如不同时间下该地点行人或者车辆停放之类的不同,这种是不需要标记的)

思路:

1、将两张照片旋转对齐,使大小角度一致

2、将处理后的照片使用模型识别(需要提前做好模型训练),专门识别出违建目标

3、比对两张图片识别出来的目标,将多出来的目标标红,少的目标标绿

代码:

1、stage1.py
import cv2
import numpy as np
import matplotlib.pyplot as plt
# stage1 将图片比对原始图片,转化大小角度之后保存
# 加载图片A和B
imgA = cv2.imread('../images/origin.jpg')
imgB = cv2.imread('../images/update1.jpg')

# 特征点检测和匹配
# 创建了一个 ORB 检测器对象。
detector = cv2.ORB_create()
# orb.detectAndCompute() 函数来检测关键点并计算描述符。
keypointsA, descriptorsA = detector.detectAndCompute(imgA, None)
keypointsB, descriptorsB = detector.detectAndCompute(imgB, None)
# 创建基于暴力匹配的特征匹配器
matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
# 使用 bf.match(des1, des2) 进行特征匹配,并根据距离排序匹配结果。
matches = matcher.match(descriptorsA, descriptorsB)
# sorted() 函数对特征匹配结果进行排序。在这里,matches 是一个特征匹配对象的列表,每个对象包含了匹配的两个特征点以及它们之间的距离信息。
matches = sorted(matches, key=lambda x: x.distance)
pointsA = np.float32([keypointsA[m.queryIdx].pt for m in matches]).reshape(-1, 1, 2)
pointsB = np.float32([keypointsB[m.trainIdx].pt for m in matches]).reshape(-1, 1, 2)

# 对齐图像B
M, mask = cv2.findHomography(pointsB, pointsA, cv2.RANSAC, 5.0)
# 对一张图像进行透视变换,使其与另一张图像对齐
alignedImgB = cv2.warpPerspective(imgB, M, (imgA.shape[1], imgA.shape[0]))
#cv2.imwrite("stage1.png", alignedImgB)

# 找到重叠区域的边界
mask_gray = cv2.cvtColor(alignedImgB, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(mask_gray, 1, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
x, y, w, h = cv2.boundingRect(contours[0])

# 裁剪出图二重叠部分
overlap_region2 = alignedImgB[y:y+h, x:x+w]

# 保存结果
cv2.imwrite('overlap_region2.jpg', overlap_region2)

# 裁剪出图一重叠部分
overlap_region1 = imgA[y:y+h, x:x+w]

# 保存结果
cv2.imwrite('overlap_region1.jpg', overlap_region1)






结果:

2、stage2.py
# stage2 将原始图片的彩钢瓦识别后提取

import cv2
from ultralytics import YOLO
from PIL import Image

model = YOLO('../../illegal-building/train2560_100_3/weights/best.pt')
image = Image.open('../matched_org_image1.jpg')
image2 = Image.open('../matched_org_image2.jpg')

results = model.predict(source=image2, save=True, save_txt=True, classes=0, line_width=5, iou=0.1)
print("======")
print(results)
结果:

比对识别出来的目标框

3、stage3.py
# stage3 比对两张图片的识别框
# 相比与原始图像多出来的框,和少的框,绘制到第二张图片上
# 多出来的用红色标记、少了的用绿色标记
import cv2

# 将读取的标注信息放的数组里
def readtxttoarray(path):
    array = []
    # 打开文件进行读取
    with open(path, 'r') as file:
        # 逐行读取文件内容并添加到数组中
        for line in file:
            rects = [float(rect) for rect in line.strip().split(" ")]
            array.append(rects)  # 去除每行末尾的换行符并添加到数组中
    return array

def is_within_range(num1, num2):
    """
    判断两个数之间的误差是否在指定阈值范围内
    :param num1: 第一个数
    :param num2: 第二个数
    :param threshold: 误差阈值,默认为0.02
    :return: 如果两个数之间的误差小于等于阈值,则返回True,否则返回False
    """
    # 计算两个数的差的绝对值
    diff = abs(num1 - num2)
    threshold = 0.02
    # 判断差值是否小于等于阈值
    return diff <= threshold

def check_intersection(box1, box2):
    # 提取边界框坐标
    a1, x1, y1, w1, h1 = box1
    a2, x2, y2, w2, h2 = box2
    # 计算水平方向上的投影
    x_overlap = max(0, min(x1 + w1, x2 + w2) - max(x1, x2))
    # 尺码、颜色:m粉白
    # 计算垂直方向上的投影
    y_overlap = max(0, min(y1 + h1, y2 + h2) - max(y1, y2))

    # 如果两个投影都有重叠,则说明存在交集
    return x_overlap > 0 and y_overlap > 0

# 如果每个标注点相差在0.02之间则认为是同一个框
# 获取在原始图片上有但是在更新后的图片上没有的标注信息
def getdiffbox(org_content, update_content):
    retbox = []
    for box in org_content:
        a = True;
        for rect in update_content:
            # 计算两个框是否相交
            if check_intersection(box, rect):
                # if (is_within_range(box[1], rect[1])and is_within_range(box[2], rect[2])and is_within_range(box[3], rect[3])and is_within_range(box[4], rect[4])):
                a = False
                break
        if a:
            retbox.append(box)
    return retbox

category = {
    0: "weijian",
    1: "lajiduifang",
    2: "zawuduifang",
    3: "piaofuwu",
    4: "shuishenzhiwu",
    5: "shatuluolu",
    6: "jianzhulaji",
    7: "lagua",
    8: "zhongzhi",
    9: "jieganfenshao",
}

# 将得到的框绘制到第二张图上
# 读取图像
def drawboxonfile(path, diff_box, color):
    img = cv2.imread(path)
    for box in diff_box:
        x_center = float(box[1]) * img.shape[1]  # 相对于图像宽度的中心坐标
        y_center = float(box[2]) * img.shape[0]  # 相对于图像高度的中心坐标
        width = float(box[3]) * img.shape[1]  # 相对于图像宽度的边界框宽度
        height = float(box[4]) * img.shape[0]  # 相对于图像高度的边界框高度

        # 计算边界框的左上角和右下角坐标
        x1 = int(x_center - width / 2)
        y1 = int(y_center - height / 2)
        x2 = int(x_center + width / 2)
        y2 = int(y_center + height / 2)
        # 绘制边界框和类别名称
        cv2.rectangle(img, (x1, y1), (x2, y2), color, 3)
        cv2.putText(img, category[(int)(box[0])], (x1, y1 - 10),
                    cv2.FONT_HERSHEY_SIMPLEX,
                    1,
                    color,
                    4, )
    # 显示带有标注信息的图像

    cv2.imwrite('result.jpg', img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

# 定义一个空数组用于存储文件内容
org_content = readtxttoarray("runs/detect/predict5/labels/matched_org_image1.txt")

# 定义一个空数组用于存储文件内容
# 
update_content = readtxttoarray("runs/detect/predict4/labels/matched_org_image2.txt")

diff_box = getdiffbox(org_content, update_content)
raise_box = getdiffbox(update_content, org_content)

drawboxonfile("../matched_org_image1.jpg", diff_box, (0, 255, 0))
drawboxonfile("result.jpg", raise_box, (0, 0, 255))
结果:

总结:

由于模型精确度不高,结果差强人意,但这个思路应该有可以借鉴的地方,遂整理一下

  • 11
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
要在OpenCV中使用YOLO进行图像检测,可以按照以下步骤进行: 1. 安装OpenCV和YOLO 2. 加载YOLO网络和权重文件,初始化检测器 ```cpp cv::dnn::Net net = cv::dnn::readNetFromDarknet(yolo_cfg_path, yolo_weights_path); ``` 3. 读取图像,将其转换为blob格式并传递给网络进行检测 ```cpp cv::Mat image = cv::imread(image_path); cv::Mat blob = cv::dnn::blobFromImage(image, 1 / 255.0, cv::Size(416, 416), cv::Scalar(0, 0, 0), true, false); net.setInput(blob); cv::Mat detection = net.forward(); ``` 4. 解析检测结果并绘制边界框 ```cpp float confidence_threshold = 0.5; std::vector<int> class_ids; std::vector<float> confidences; std::vector<cv::Rect> boxes; for (int i = 0; i < detection.rows; ++i) { cv::Mat row = detection.row(i); cv::Mat scores = row.colRange(5, detection.cols); cv::Point class_id; double confidence; cv::minMaxLoc(scores, nullptr, &confidence, nullptr, &class_id); if (confidence > confidence_threshold) { int x_center = static_cast<int>(row.at<float>(0) * image.cols); int y_center = static_cast<int>(row.at<float>(1) * image.rows); int width = static_cast<int>(row.at<float>(2) * image.cols); int height = static_cast<int>(row.at<float>(3) * image.rows); int x_left = x_center - width / 2; int y_top = y_center - height / 2; class_ids.push_back(class_id.x); confidences.push_back(confidence); boxes.emplace_back(x_left, y_top, width, height); } } for (int i = 0; i < boxes.size(); ++i) { cv::rectangle(image, boxes[i], cv::Scalar(0, 0, 255), 2); } ``` 要识别两张图片不同之处,可以将两张图片都传递给YOLO进行检测,然后比较检测结果的差异。可以使用OpenCV的图像差分函数(cv::absdiff)来比较两张图像的像素值差异,并将差异区域作为输入传递给YOLO进行检测,然后在原始图像上绘制检测结果的边界框。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值