C ++中的二进制图像处理

时间:2017-11-06 13:09:24

标签: c++ image opencv

我有一组来自相机的二进制图像,并由相机预先设定阈值。然后我使用OpenCV查找每个图像中的轮廓和轮廓中心的坐标。

但我遇到的问题是,这种过程非常缓慢。相机的工作速度为170 fps,分辨率为2048 * 1088。

我知道实时执行此操作时数据量巨大。有什么好的库可以用来加速它,因为我需要的只是坐标。我需要丢弃所有灰度信息并仅提取每个图像中轮廓中心的坐标。

如果有人可以提供我的想法,我将不胜感激。

根据评论中的要求,我的部分代码将添加到此处:

图像采集部分

#include <opencv2\opencv.hpp>
#include <stdio.h>
#include "xiApiPlusOcv.hpp"
#include <ctime>

xiAPIplusCameraOcv cam;
Mat frame;
vector<Mat> frames;
...
cam.StartAcquisition();
startTime = clock();

for (int j = 0; j < 600; j++)
{
    frame = cam.GetNextImageOcvMat();
    frames.push_back(frame.clone());

    frame.release();
}
cam.StopAcquisition();
cam.Close();

我正在使用XIMEA的CMOS单声道摄像头,在这里我通过相机的RAM缓冲对600帧进行采样。收购种子最高可达170 fps。然后我把所有其他处理都放在这之后:

vector<Mat> masks(frames.size());
for (int s = 0; s < frames.size(); s++)
{
    cvtColor(frames[s], masks[s], CV_GRAY2BGR);
    vector<Vec4i> hierarchy;
    vector<vector<Point> > contours;
    findContours(frames[s], contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);

    vector<Moments> M(contours.size());
    vector<Point2f> MC(contours.size());
    for (size_t i = 0; i < contours.size(); i++)
    {
        M[i] = moments(contours[i]);
    }

    for (size_t i = 0; i < contours.size(); i++)
    {
        MC[i] = Point2f(M[i].m10 / M[i].m00, M[i].m01 / M[i].m00);
    }

    for (size_t i = 0; i < contours.size(); ++i)
    {
        // Calculate the area of each contour
        double area = contourArea(contours[i]);
        // Ignore contours that are too small or too large
        if (area < 1e2 || 1e5 < area) continue;
        // Draw each contour only for visualisation purposes
        drawContours(masks[s], contours, static_cast<int>(i), Scalar(0, 0, 255), 2, 8, hierarchy, 0);
        circle(masks[s], MC[i], 4, Scalar(0, 0, 255), -1);
    }
}

如果我发现离线轮廓,就像上面显示的那样,我对结果感到满意。但是只能记录几分钟的非常短的视频,这意味着无法进行更长时间的监控。

如果我将处理与采集一起移动到一个不确定的循环中,它只给我30-40 fps,这是不可接受的。

我的投资回报率中所需轮廓的数量约为10。 我的应用的最终目标是在距离约50米的地方监视框架内的几个飞行物体。我认为它们的坐标都很重要。

我在i7-5500U 2.4GHz CPU的笔记本电脑上运行。

更新: 这是一张来自相机的二进制图像,用于在非常基本的试验中监控一只大黄蜂。在正常的试验中,相机框架内可能会有数十只飞虫。 one binarized frame of the captured bumble bee

1 个答案:

答案 0 :(得分:1)

你的代码中有很多的东西真的很奇怪(见下文)。 但是:

您只需调用connectedComponentsWithStats来计算质心:

vector<Mat> frames;
...
cv::Mat1i labels;
cv::Mat1i stats;
cv::Mat1d centroids;

for(size_t i=0; i<frames.size(); ++i) 
{
    // centroids will contain in each row the coordinates x,y of the centroids.
    int n_labels = cv::connectedComponentsWithStats(frame[i], labels, stats, centroids);                

    // Remember that label 0 is the background... not really useful.
    for(int j=1; j<n_labels; ++j)  
    {
        // Filter by area
        int area = stats(j, cv::CC_STAT_AREA);
        if (area < 1e2 || 1e5 < area) continue;     

        // Do something with the centroid
        cv::Point2d centroid(centroids(j,0), centroids(j,1));
        ...
    } 
}
  • 我认为您的图片类型为CV_8UC1,因为您正在使用它们。否则请致电cv::Mat1b temp; cvtColor(frame[i], temp, cv::COLOR_BGR2GRAY);,然后使用temp
  • 你实际上从未将图像二值化。
  • 为什么要在cvtColor(frames[s], masks[s], CV_GRAY2BGR);中将灰色转换为rgb?面具是单通道!
  • 您的功能大部分用于调试。你应该避免这些东西用于关键代码。
  • CV_CHAIN_APPROX_NONE寻找轮廓会浪费很多空间。
  • 只需使用比connectedComponentWithStats快得多的findContours,并且已经为您提供了每个blob的区域和质心。