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

binary image manipulation in C++

本文关键字:图像处理 二进制 C++      更新时间:2023-10-16

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

但我的问题是,这种过程非常缓慢。该相机以每秒170帧的速度工作,分辨率为2048*1088。

我知道当我实时这样做时,数据量是巨大的。有没有什么好的库可以用来加快速度,因为我只需要坐标。我需要扔掉所有的灰度信息,只提取每个图像中轮廓中心的坐标。

如果有人能提供我和想法,我将不胜感激。

正如评论中所要求的,我的部分代码被添加到这里:

图像获取部分

#include <opencv2opencv.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帧/秒。然后我把所有其他处理作为:

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帧/秒,这是不可接受的。

在我的ROI中,所需轮廓的数量大约是10个。我的应用程序的最终目标是监视框架内大约50米距离的几个飞行物体。它们的坐标就是我认为的全部。

我在一台带有i7-500U 2.4GHz CPU的笔记本电脑上运行这个。

更新:这是一张二值化的图像,来自于在一次非常基本的试验中监测一只大黄蜂的相机。在正常的试验中,相机框架内可能有几十只飞虫。捕获的大黄蜂的一个二进制帧

在您的代码中有很多的东西(见下文)。但是:

只需调用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?面具是单通道的
  • 您的函数所做的大部分工作都是为了调试。对于关键代码,应该避免使用这些东西
  • CCD_ 6用于寻找轮廓将浪费大量空间
  • 只需使用connectedComponentWithStats,它比findContours快得多,并且已经为您提供了每个斑点的面积和质心