nim_duilib/examples/contour/blob/BlobContour.cpp
2025-03-16 16:42:44 +08:00

276 lines
6.5 KiB
C++

#include "BlobContour.h"
BlobContour::BlobContour()
{
m_startPoint.x = 0;
m_startPoint.y = 0;
m_area = -1;
m_perimeter = -1;
m_moments.m00 = -1;
m_parent = NULL;
}
BlobContour::BlobContour(const cv::Point& startPoint, const cv::Size& imageRes) : m_contour(1)
{
m_startPoint.x = startPoint.x;
m_startPoint.y = startPoint.y;
m_area = -1;
m_perimeter = -1;
m_moments.m00 = -1;
m_parent = NULL;
//Empirical calculations
if (imageRes.width == -1 || imageRes.width*imageRes.height > 62500) {
m_contour[0].reserve(600);
}
else {
//I reserve a portion of the image's area
m_contour[0].reserve(imageRes.height*imageRes.width/4);
}
}
//! Copy constructor
BlobContour::BlobContour(BlobContour* source)
{
if (source != NULL) {
*this = *source;
}
}
BlobContour::BlobContour(const BlobContour& source)
{
m_area = source.m_area;
m_contour = source.m_contour;
m_contourPoints = source.m_contourPoints;
m_moments = source.m_moments;
m_perimeter = source.m_perimeter;
m_startPoint = source.m_startPoint;
m_parent = NULL;
}
BlobContour::~BlobContour()
{
}
//! Copy operator
BlobContour& BlobContour::operator=(const BlobContour& source)
{
if (this != &source) {
m_startPoint = source.m_startPoint;
m_area = source.m_area;
m_perimeter = source.m_perimeter;
m_moments = source.m_moments;
m_contour = source.m_contour;
m_contourPoints = source.m_contourPoints;
}
m_parent = NULL;
return *this;
}
/**
- FUNCIÓ: addChainCode
- FUNCIONALITAT: Add chain code to contour
- PARÀMETRES:
-
- RESULTAT:
-
- RESTRICCIONS:
-
- AUTOR: rborras
- DATA DE CREACIÓ: 2008/05/06
- MODIFICACIÓ: Data. Autor. Descripció.
*/
void BlobContour::addChainCode(ChainCode chaincode)
{
m_contour[0].push_back(chaincode);
}
//! Clears chain code contour and points
void BlobContour::reset()
{
m_contour.clear();
m_contourPoints.clear();
}
/**
- FUNCIÓ: getPerimeter
- FUNCIONALITAT: Get perimeter from chain code. Diagonals sum sqrt(2) and horizontal and vertical codes 1
- PARÀMETRES:
-
- RESULTAT:
-
- RESTRICCIONS:
-
- AUTOR: rborras
- DATA DE CREACIÓ: 2008/04/30
- MODIFICACIÓ: Data. Autor. Descripció.
- NOTA: Algorithm derived from "Methods to estimate area and perimeters of blob-like objects: A comparison", L.Yang
*/
double BlobContour::getPerimeter()
{
// is calculated?
if (m_perimeter != -1) {
return m_perimeter;
}
if (isEmpty()) {
return 0;
}
m_perimeter = cv::arcLength(getContourPoints(), true);
return m_perimeter;
}
/**
- FUNCIÓ: getArea
- FUNCIONALITAT: Computes area from chain code
- PARÀMETRES:
-
- RESULTAT:
- May give negative areas for clock wise contours
- RESTRICCIONS:
-
- AUTOR: rborras
- DATA DE CREACIÓ: 2008/04/30
- MODIFICACIÓ: Data. Autor. Descripció.
- NOTA: Algorithm derived from "Properties of contour codes", G.R. Wilson
*/
double BlobContour::getArea()
{
// is calculated?
if (m_area != -1) {
return m_area;
}
if (isEmpty()) {
return 0;
}
m_area = std::fabs(contourArea(getContourPoints(), false));
return m_area;
}
//! Get contour moment (p,q up to MAX_CALCULATED_MOMENTS)
double BlobContour::getMoment(int p, int q)
{
// is a valid moment?
if (p < 0 || q < 0 || p > MAX_MOMENTS_ORDER || q > MAX_MOMENTS_ORDER) {
return -1;
}
if (isEmpty()) {
return 0;
}
// it is calculated?
if (m_moments.m00 == -1) {
//cvMoments(getContourPoints(), &m_moments);
m_moments = cvMoments(moments(getContourPoints(), true));
}
return cvGetSpatialMoment(&m_moments, p, q);
}
const PointList BlobContour::EMPTY_LIST = PointList();
//! Calculate contour points from crack codes
const PointList& BlobContour::getContourPoints()
{
if (m_contour.size() == 0) {
return EMPTY_LIST;
}
if (m_contourPoints.size() != 0) {
return m_contourPoints[0];
}
m_contourPoints.push_back(PointList());
m_contourPoints[0].reserve(m_contour[0].size() + 1);
m_contourPoints[0].push_back(m_startPoint);
ChainCodeList::iterator it,en;
it = m_contour[0].begin();
en = m_contour[0].end();
cv::Point pt = m_contourPoints[0][m_contourPoints.size() - 1];
for (; it != en; ++it) {
pt = chainCode2Point(pt, *it);
m_contourPoints[0].push_back(pt);
}
return m_contourPoints[0];
}
Contours& BlobContour::getContours()
{
getContourPoints();
return m_contourPoints;
}
void BlobContour::shiftBlobContour(int x, int y)
{
m_startPoint.x += x;
m_startPoint.y += y;
for (unsigned int j = 0; j < m_contourPoints.size(); ++j) {
for (unsigned int i = 0; i < m_contourPoints[j].size(); ++i) {
m_contourPoints[j][i] += cv::Point(x, y);
}
}
}
ChainCode points2ChainCode(const cv::Point& p1, const cv::Point& p2)
{
// /* Luca Nardelli & Saverio Murgia
// Freeman Chain Code:
// 321 Values indicate the chain code used to identify next pixel location.
// 4-0 If I join 2 blobs I can't just append the 2nd blob chain codes, since they will still start
// 567 from the 1st blob start point
// */
cv::Point diff = cv::Point(p2.x-p1.x, p2.y-p1.y);
if (diff.x == 1 && diff.y == 0) {
return 0;
}
else if (diff.x == 1 && diff.y == -1) {
return 1;
}
else if (diff.x == 0 && diff.y == -1) {
return 2;
}
else if (diff.x == -1 && diff.y == -1) {
return 3;
}
else if (diff.x == -1 && diff.y == 0) {
return 4;
}
else if (diff.x == -1 && diff.y == 1) {
return 5;
}
else if (diff.x == 0 && diff.y == 1) {
return 6;
}
else if (diff.x == 1 && diff.y == 1) {
return 7;
}
else {
return 200;
}
}
cv::Point chainCode2Point(const cv::Point& origin, ChainCode code) {
// /* Luca Nardelli & Saverio Murgia
// Freeman Chain Code:
// 321 Values indicate the chain code used to identify next pixel location.
// 4-0 If I join 2 blobs I can't just append the 2nd blob chain codes, since they will still start
// 567 from the 1st blob start point
// */
cv::Point pt = origin;
switch (code) {
case 0: pt.x++; break;
case 1: pt.x++; pt.y--; break;
case 2: pt.y--; break;
case 3: pt.x--; pt.y--; break;
case 4: pt.x--; break;
case 5: pt.x--; pt.y++; break;
case 6: pt.y++; break;
case 7: pt.x++; pt.y++; break;
}
return pt;
}