十字标是正的

def detect_cross_by_projection(image_path, k=1.0, sigma=1.0):
    # 1. 读取图像并转换为灰度图
    image = cv2.imread(image_path)
    if image is None:
        print("无法读取图像,请检查路径!")
        return None
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # 图片旋转5°
    rows, cols = image.shape[:2]
    M = cv2.getRotationMatrix2D((cols/2, rows/2), 3, 1)
    image = cv2.warpAffine(gray, M, (cols, rows))

    # 2. 边缘检测(Canny)
    edges = cv2.Canny(image, 100, 200, apertureSize=3)

    # 3. 统计行和列的边缘像素和(投影)
    row_projection = np.sum(edges, axis=1)  # 行投影
    col_projection = np.sum(edges, axis=0)  # 列投影

    # 4. 高斯平滑投影曲线
    row_projection_smooth = cv2.GaussianBlur(row_projection.astype(np.float32), (0, 0), sigma)
    col_projection_smooth = cv2.GaussianBlur(col_projection.astype(np.float32), (0, 0), sigma)

    # 5. 检测峰(局部极大且大于 mean + k*std)
    def detect_peaks(projection, k):
        mean = np.mean(projection)
        std = np.std(projection)
        threshold = mean + k * std
        peaks = []
        for i in range(1, len(projection) - 1):
            if projection[i] > projection[i-1] and projection[i] > projection[i+1] and projection[i] > threshold:
                peaks.append(i)
        return peaks

    row_peaks = detect_peaks(row_projection_smooth, k)
    col_peaks = detect_peaks(col_projection_smooth, k)

    # 6. 取最显著的行峰和列峰
    if not row_peaks or not col_peaks:
        print("未检测到峰!")
        return None

    # 选择最显著的峰(投影值最大的峰)
    row_peak = row_peaks[np.argmax(row_projection_smooth[row_peaks])]
    col_peak = col_peaks[np.argmax(col_projection_smooth[col_peaks])]

    # 7. 计算交点并可视化
    cross_point = (col_peak, row_peak)

    # 绘制检测结果
    result_image = image.copy()
    cv2.circle(result_image, cross_point, 10, (0, 0, 255), -1)  # 绘制交点
    cv2.line(result_image, (0, row_peak), (result_image.shape[1], row_peak), (0, 0, 255), 2)  # 绘制行线
    cv2.line(result_image, (col_peak, 0), (col_peak, result_image.shape[0]), (0, 0, 255), 2)  # 绘制列线

    # 8. 可视化投影曲线和峰
    plt.figure(figsize=(12, 6))

    # 行投影
    plt.subplot(1, 2, 1)
    plt.plot(row_projection, label="Row Projection")
    plt.plot(row_projection_smooth, label="Smoothed Row Projection")
    plt.axhline(y=np.mean(row_projection_smooth) + k * np.std(row_projection_smooth), color='r', linestyle='--', label="Threshold")
    plt.scatter(row_peaks, row_projection_smooth[row_peaks], color='g', label="Peaks")
    plt.title("Row Projection")
    plt.legend()

    # 列投影
    plt.subplot(1, 2, 2)
    plt.plot(col_projection, label="Column Projection")
    plt.plot(col_projection_smooth, label="Smoothed Column Projection")
    plt.axhline(y=np.mean(col_projection_smooth) + k * np.std(col_projection_smooth), color='r', linestyle='--', label="Threshold")
    plt.scatter(col_peaks, col_projection_smooth[col_peaks], color='g', label="Peaks")
    plt.title("Column Projection")
    plt.legend()

    plt.tight_layout()
    plt.show()

    # 9. 显示中间图和结果图
    cv2.imshow("image", image)
    cv2.imshow("Result", result_image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    print("Detected Cross Point:", cross_point)

原图在这里插入图片描述
统计垂直方向和水平方向
在这里插入图片描述
马上就能找到中点了

但是一旦图像旋转了3°,这个算法立马失效,比如下面的

在这里插入图片描述
AI 生成的c++版(未验证)

以下是将Python代码转换为C++的实现,功能包括图像处理、边缘检测、投影分析及交叉点检测:

#include <opencv2/opencv.hpp>
#include <vector>
#include <algorithm>
#include <numeric>
#include <cmath>

std::vector<int> detectPeaks(const std::vector<float>& projection, float k) {
    float sum = std::accumulate(projection.begin(), projection.end(), 0.0f);
    float mean = sum / projection.size();
    float sq_sum = std::inner_product(projection.begin(), projection.end(), projection.begin(), 0.0f);
    float std_dev = std::sqrt(sq_sum / projection.size() - mean * mean);
    float threshold = mean + k * std_dev;
    
    std::vector<int> peaks;
    for (int i = 1; i < projection.size() - 1; ++i) {
        if (projection[i] > projection[i-1] && projection[i] > projection[i+1] && projection[i] > threshold) {
            peaks.push_back(i);
        }
    }
    return peaks;
}

void detectCrossByProjection(const std::string& imagePath, float k = 1.0f, float sigma = 1.0f) {
    cv::Mat image = cv::imread(imagePath);
    if (image.empty()) {
        std::cerr << "无法读取图像,请检查路径!" << std::endl;
        return;
    }

    cv::Mat gray;
    cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);

    cv::Point2f center(gray.cols / 2.0f, gray.rows / 2.0f);
    cv::Mat rotMat = cv::getRotationMatrix2D(center, 3, 1);
    cv::warpAffine(gray, gray, rotMat, gray.size());

    cv::Mat edges;
    cv::Canny(gray, edges, 100, 200, 3);

    cv::Mat rowProjection, colProjection;
    cv::reduce(edges, rowProjection, 1, cv::REDUCE_SUM, CV_32F);
    cv::reduce(edges, colProjection, 0, cv::REDUCE_SUM, CV_32F);

    cv::Mat rowProjectionSmooth, colProjectionSmooth;
    cv::GaussianBlur(rowProjection, rowProjectionSmooth, cv::Size(0, 0), sigma);
    cv::GaussianBlur(colProjection, colProjectionSmooth, cv::Size(0, 0), sigma);

    std::vector<float> rowVec, colVec;
    rowProjectionSmooth.copyTo(rowVec);
    colProjectionSmooth.copyTo(colVec);

    std::vector<int> rowPeaks = detectPeaks(rowVec, k);
    std::vector<int> colPeaks = detectPeaks(colVec, k);

    if (rowPeaks.empty() || colPeaks.empty()) {
        std::cerr << "未检测到峰!" << std::endl;
        return;
    }

    auto maxRowIt = std::max_element(rowPeaks.begin(), rowPeaks.end(), 
        [&rowVec](int a, int b) { return rowVec[a] < rowVec[b]; });
    auto maxColIt = std::max_element(colPeaks.begin(), colPeaks.end(),
        [&colVec](int a, int b) { return colVec[a] < colVec[b]; });

    int rowPeak = *maxRowIt;
    int colPeak = *maxColIt;
    cv::Point crossPoint(colPeak, rowPeak);

    cv::Mat resultImage = gray.clone();
    cv::cvtColor(resultImage, resultImage, cv::COLOR_GRAY2BGR);
    cv::circle(resultImage, crossPoint, 10, cv::Scalar(0, 0, 255), -1);
    cv::line(resultImage, cv::Point(0, rowPeak), cv::Point(resultImage.cols, rowPeak), cv::Scalar(0, 0, 255), 2);
    cv::line(resultImage, cv::Point(colPeak, 0), cv::Point(colPeak, resultImage.rows), cv::Scalar(0, 0, 255), 2);

    cv::imshow("Edges", edges);
    cv::imshow("Result", resultImage);
    cv::waitKey(0);
    cv::destroyAllWindows();

    std::cout << "Detected Cross Point: " << crossPoint << std::endl;
}

关键实现说明

图像处理部分

  • 使用cv::imread加载图像,cv::cvtColor转换为灰度图
  • 通过cv::getRotationMatrix2D实现图像旋转3度(非原代码的5度)

边缘检测与投影

  • cv::Canny进行边缘检测
  • cv::reduce计算行/列投影(分别沿垂直和水平方向求和)

峰值检测

  • 计算投影数据的均值与标准差
  • 按阈值mean + k*std筛选局部极大值点

结果可视化

  • 使用cv::circle标记交点
  • cv::line绘制水平和垂直参考线

注意事项

  1. 需要OpenCV库支持(建议4.x版本)
  2. 输入参数k控制峰值检测灵敏度
  3. 可视化部分仅保留核心结果,移除了原Python代码的Matplotlib绘图

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐