OpenCV绘制箭头

转载自:http://tmjfzy.blog.163.com/blog/static/664470252012225101017794/

代码:

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace cv;

void drawArrow(cv::Mat& img, cv::Point pStart, cv::Point pEnd, int len, int alpha,
    cv::Scalar& color, int thickness = 1, int lintType = 8);

int main(int argc, char** argv)
{
    cv::Mat mat = imread("test.jpg");
    namedWindow("test");
    imshow("test", mat);

    Mat m(400, 400, CV_8UC3, Scalar(0, 0, 0));
    Point pStart(380, 100), pEnd(100, 250);
    Scalar lineColor(0, 255, 255);
    drawArrow(m, pStart, pEnd, 10, 45, lineColor);
    pStart = Point(100, 100);
    pEnd = Point(320, 190);
    lineColor = Scalar(0, 0, 255);
    drawArrow(m, pStart, pEnd, 25, 30, lineColor, 2, CV_AA);
    pStart = Point(200, 420);
    pEnd = Point(370, 170);
    lineColor = Scalar(255, 0, 255);
    drawArrow(m, pStart, pEnd, 17, 15, lineColor, 1, 4);
    imshow("draw arrow", m);

    waitKey();
    return 0;
}


void drawArrow(cv::Mat& img, cv::Point pStart, cv::Point pEnd, int len, int alpha, cv::Scalar& color, int thickness, int lineType)
{
    const double PI = 3.1415926;
    Point arrow;
    //计算 θ 角(最简单的一种情况在下面图示中已经展示,关键在于 atan2 函数,详情见下面)   
    double angle = atan2((double)(pStart.y - pEnd.y), (double)(pStart.x - pEnd.x));

    line(img, pStart, pEnd, color, thickness, lineType);

    //计算箭角边的另一端的端点位置(上面的还是下面的要看箭头的指向,也就是pStart和pEnd的位置) 
    arrow.x = pEnd.x + len * cos(angle + PI * alpha / 180);

    arrow.y = pEnd.y + len * sin(angle + PI * alpha / 180);

    line(img, pEnd, arrow, color, thickness, lineType);

    arrow.x = pEnd.x + len * cos(angle - PI * alpha / 180);

    arrow.y = pEnd.y + len * sin(angle - PI * alpha / 180);

    line(img, pEnd, arrow, color, thickness, lineType);
}

结果
这里写图片描述

### 使用 OpenCV 进行箭头检测和识别 为了实现箭头的检测与识别,可以采用一系列图像处理技术和特征提取方法。具体来说,可以通过形态学操作、轮廓查找以及几何形状分析来完成这一目标。 #### 图像预处理 首先对输入图像进行灰度化转换并应用高斯模糊以减少噪声干扰[^1]: ```python import cv2 import numpy as np def preprocess_image(image_path): img = cv2.imread(image_path, 0) # Read image in grayscale mode blurred_img = cv2.GaussianBlur(img, (5, 5), 0) # Apply Gaussian blur to reduce noise _, binary_img = cv2.threshold(blurred_img, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) kernel = np.ones((3, 3), np.uint8) morphed_img = cv2.morphologyEx(binary_img, cv2.MORPH_CLOSE, kernel) return morphed_img ``` 此部分代码实现了图像的初步清理工作,使得后续步骤能够更准确地定位箭头位置。 #### 轮廓发现与筛选 接着,在经过预处理后的二值图上寻找所有可能存在的闭合区域即轮廓,并从中挑选出具有特定属性的对象作为候选箭头: ```python def find_arrow_contours(preprocessed_img): contours, _ = cv2.findContours(preprocessed_img.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) arrow_candidates = [] for cnt in contours: approx = cv2.approxPolyDP(cnt, 0.02 * cv2.arcLength(cnt, True), True) if len(approx) >= 4 and len(approx) <= 6: # Arrow usually has between 4-6 vertices after approximation. area = cv2.contourArea(cnt) if area > 100: # Filter out small regions that are unlikely to be arrows. rect = cv2.minAreaRect(cnt) box = cv2.boxPoints(rect) box = np.intp(box) aspect_ratio = max(rect[1]) / min(rect[1]) if 1.5 < aspect_ratio < 5: # Arrows tend to have a certain range of aspect ratios. arrow_candidates.append((approx, box)) return arrow_candidates ``` 上述逻辑基于箭头通常具有的顶点数量范围及其面积大小来进行过滤;同时考虑到箭头形状的特点——较长而窄的比例关系进一步缩小了潜在匹配项的数量。 #### 特征验证与分类决策 最后一步是对每一个符合条件的候选项执行更加严格的检验过程,比如检查是否存在明显的指向性结构等特性,从而最终确认是否为真正的箭头对象[^2][^3]: ```python def verify_arrows(candidates, original_img): verified_arrows = [] for candidate, bounding_box in candidates: mask = np.zeros_like(original_img) cv2.drawContours(mask, [candidate], -1, color=255, thickness=cv2.FILLED) masked_region = cv2.bitwise_and(original_img, mask) hull = cv2.convexHull(candidate) convexity_defects = cv2.convexityDefects(candidate, hull) if convexity_defects is not None and len(convexity_defects) == 1: start_point_index, end_point_index, farthest_point_index, distance = tuple(map(int, convexity_defects[0])) start_point = tuple(candidate[start_point_index % len(candidate)][0]) end_point = tuple(candidate[end_point_index % len(candidate)][0]) angle_between_points = calculate_angle(start_point, end_point) if abs(angle_between_points - 90) < 30 or abs(angle_between_points - 270) < 30: verified_arrows.append(bounding_box) return verified_arrows def calculate_angle(point_a, point_b): delta_x = point_b[0] - point_a[0] delta_y = point_b[1] - point_a[1] radians = math.atan2(delta_y, delta_x) degrees = math.degrees(radians) while degrees < 0: degrees += 360 return round(degrees) if __name__ == "__main__": input_image_path = 'path_to_input_image' preprocessed = preprocess_image(input_image_path) contour_results = find_arrow_contours(preprocessed) final_arrows = verify_arrows(contour_results, cv2.cvtColor(preprocess_image(input_image_path), cv2.COLOR_GRAY2BGR)) output_with_boxes = draw_resulting_boxes(final_arrows, cv2.imread(input_image_path)) cv2.imshow('Detected Arrows', output_with_boxes) cv2.waitKey(0) cv2.destroyAllWindows() ``` 这里引入了一个额外的功能用于绘制边界框以便于可视化结果。`verify_arrows()` 函数内部还包含了对于凸缺陷(Convex Defects)的评估机制,这有助于区分其他相似但不符合条件的目标物体。此外,通过计算两点间夹角的方式判断方向性也是确保准确性的重要手段之一。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值