沿明亮像素拟合线条
Fitting lines along bright pixels
我试图通过在亮像素簇的最长轴上拟合线来检测图像中的短 "filaments"。有没有办法使用可用的计算机视觉库(即 OpenCV)中的工具来做到这一点?
您可以:
- 找到每个连通分量,
findContours
- 找到每个连通分量的最小定向边界框,
minAreaRect
- 画一条通过中心的线(平行于最长边)。
结果:
既然你提到了:
I'd like to reduce each "blob" to an object with the attributes 1) length 2) centroid 3) angle
我将一些功能封装到 class Blob
中。这是代码:
#include <opencv2/opencv.hpp>
#include <vector>
using namespace std;
using namespace cv;
struct Blob
{
float _length;
Point2f _centroid;
float _angle;
Blob(float length, const Point2f& centroid, float angle) :
_length(length), _centroid(centroid), _angle(angle) {};
Blob(const Blob& other) :
_length(other._length), _centroid(other._centroid), _angle(other._angle) {};
Blob(const RotatedRect& r)
{
_centroid = r.center;
_angle = r.angle*CV_PI / 180.;
_length = r.size.height;
if (r.size.width >= r.size.height)
{
_angle = (CV_PI / 2.0) + _angle;
_length = r.size.width;
}
}
void draw(const Mat3b& img)
{
// Draw line
Point2f p1, p2;
float b = (float)cos(_angle)*0.5f;
float a = (float)sin(_angle)*0.5f;
p1.x = _centroid.x - a*_length;
p1.y = _centroid.y + b*_length;
p2.x = _centroid.x + a*_length;
p2.y = _centroid.y - b*_length;
line(img, p1, p2, Scalar(0,0,255));
};
};
int main()
{
Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);
// Apply a threshold to remove JPEG artifacts
Mat1b img2 = img > 200;
// Prepare output image
Mat3b result;
cvtColor(img, result, COLOR_GRAY2BGR);
// Apply a small border to take care of blobs on image boundary
copyMakeBorder(img2, img2, 1, 1, 1, 1, BORDER_CONSTANT, Scalar(0));
// Find connected components
vector<vector<Point>> contours;
findContours(img2.clone(), contours, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
// The vector of blobs
vector<Blob> blobs;
for (int i = 0; i < contours.size(); ++i)
{
// Account for border
for (int j = 0; j < contours[i].size(); ++j)
{
contours[i][j] -= Point(1,1);
}
// Find minimum oriented bounding box
RotatedRect r = minAreaRect(contours[i]);
Blob b(r);
b.draw(result);
// Append to blobs
blobs.push_back(b);
}
imshow("Result", result);
waitKey();
return 0;
}
我试图通过在亮像素簇的最长轴上拟合线来检测图像中的短 "filaments"。有没有办法使用可用的计算机视觉库(即 OpenCV)中的工具来做到这一点?
您可以:
- 找到每个连通分量,
findContours
- 找到每个连通分量的最小定向边界框,
minAreaRect
- 画一条通过中心的线(平行于最长边)。
结果:
既然你提到了:
I'd like to reduce each "blob" to an object with the attributes 1) length 2) centroid 3) angle
我将一些功能封装到 class Blob
中。这是代码:
#include <opencv2/opencv.hpp>
#include <vector>
using namespace std;
using namespace cv;
struct Blob
{
float _length;
Point2f _centroid;
float _angle;
Blob(float length, const Point2f& centroid, float angle) :
_length(length), _centroid(centroid), _angle(angle) {};
Blob(const Blob& other) :
_length(other._length), _centroid(other._centroid), _angle(other._angle) {};
Blob(const RotatedRect& r)
{
_centroid = r.center;
_angle = r.angle*CV_PI / 180.;
_length = r.size.height;
if (r.size.width >= r.size.height)
{
_angle = (CV_PI / 2.0) + _angle;
_length = r.size.width;
}
}
void draw(const Mat3b& img)
{
// Draw line
Point2f p1, p2;
float b = (float)cos(_angle)*0.5f;
float a = (float)sin(_angle)*0.5f;
p1.x = _centroid.x - a*_length;
p1.y = _centroid.y + b*_length;
p2.x = _centroid.x + a*_length;
p2.y = _centroid.y - b*_length;
line(img, p1, p2, Scalar(0,0,255));
};
};
int main()
{
Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);
// Apply a threshold to remove JPEG artifacts
Mat1b img2 = img > 200;
// Prepare output image
Mat3b result;
cvtColor(img, result, COLOR_GRAY2BGR);
// Apply a small border to take care of blobs on image boundary
copyMakeBorder(img2, img2, 1, 1, 1, 1, BORDER_CONSTANT, Scalar(0));
// Find connected components
vector<vector<Point>> contours;
findContours(img2.clone(), contours, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
// The vector of blobs
vector<Blob> blobs;
for (int i = 0; i < contours.size(); ++i)
{
// Account for border
for (int j = 0; j < contours[i].size(); ++j)
{
contours[i][j] -= Point(1,1);
}
// Find minimum oriented bounding box
RotatedRect r = minAreaRect(contours[i]);
Blob b(r);
b.draw(result);
// Append to blobs
blobs.push_back(b);
}
imshow("Result", result);
waitKey();
return 0;
}