1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 23:33:05 +04:00

Adding macbeth chart detector to objdetect module from opencv_contrib (#26906)

* Added mcc to opencv modules

* Removed color correction module

* Updated parameters return type

* Added python sample for macbeth_chart_detection

* Added models.yml support to samples

* Removed unnecessary headers and classes

* fixed datatype conversion

* fixed datatype conversion

* Cleaned headers and added reference/actual colors to samples

* Added mcc tutorial

* fixed datatype and header

* replaced unsigned with int

* Aligned actual and reference color function, added imread

* Fixed shadow variable

* Updated samples

* Added last frame colors prints

* updated detector class

* Added getter functions and useNet function

* Refactoring

* Fixes in test

* fixed infinite divison issue
This commit is contained in:
Gursimar Singh
2025-03-28 13:43:30 +05:30
committed by GitHub
parent a674ae1bce
commit 69b91cabb4
31 changed files with 5754 additions and 0 deletions
@@ -47,6 +47,7 @@
#include "opencv2/core.hpp"
#include "opencv2/objdetect/aruco_detector.hpp"
#include "opencv2/objdetect/graphical_code_detector.hpp"
#include "opencv2/objdetect/mcc_checker_detector.hpp"
/**
@defgroup objdetect Object Detection
@@ -0,0 +1,300 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/*
* MIT License
*
* Copyright (c) 2018 Pedro Diamel Marrero Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef OPENCV_OBJDETECT_MCC_CHECKER_DETECTOR_HPP
#define OPENCV_OBJDETECT_MCC_CHECKER_DETECTOR_HPP
#include <opencv2/core.hpp>
#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
//---------------------------------------------------------------
// #define MCC_DEBUG
//---------------------------------------------------------------
namespace cv
{
namespace mcc
{
//! @addtogroup mcc
//! @{
/** ColorChart
*
* @brief enum to hold the type of the checker
*/
enum ColorChart
{
MCC24 = 0, ///< Standard Macbeth Chart with 24 squares
SG140, ///< DigitalSG with 140 squares
VINYL18, ///< DKK color chart with 12 squares and 6 rectangle
};
/** CChecker
*
* @brief checker object
*
* This class contains the information about the detected checkers,i.e, their
* type, the corners of the chart, the color profile, the cost, centers chart,
* etc.
*/
class CV_EXPORTS_W CChecker: public Algorithm
{
public:
CChecker() {}
virtual ~CChecker() {}
/** @brief Create a new CChecker object.
*
* @return A pointer to the implementation of the CChecker
*/
CV_WRAP static Ptr<CChecker> create();
public:
CV_WRAP virtual void setTarget(ColorChart _target) = 0;
CV_WRAP virtual void setBox(std::vector<Point2f> _box) = 0;
CV_WRAP virtual void setChartsRGB(Mat _chartsRGB) = 0;
CV_WRAP virtual void setChartsYCbCr(Mat _chartsYCbCr) = 0;
CV_WRAP virtual void setCost(float _cost) = 0;
CV_WRAP virtual void setCenter(Point2f _center) = 0;
CV_WRAP virtual ColorChart getTarget() = 0;
CV_WRAP virtual std::vector<Point2f> getBox() = 0;
/** @brief Computes and returns the coordinates of the central parts of the charts modules.
*
* This method computes transformation matrix from the checkers's coordinates (`CChecker::getBox()`)
* and find by this the coordinates of the central parts of the charts modules.
* It is used in `CCheckerDetector::draw()` and in `ChartsRGB` calculation.
*/
CV_WRAP virtual std::vector<Point2f> getColorCharts() = 0;
CV_WRAP virtual Mat getChartsRGB(bool getStats = true) = 0;
CV_WRAP virtual Mat getChartsYCbCr() = 0;
CV_WRAP virtual float getCost() = 0;
CV_WRAP virtual Point2f getCenter() = 0;
};
/** @brief struct DetectorParametersMCC is used by CCheckerDetector
*/
struct CV_EXPORTS_W_SIMPLE DetectorParametersMCC
{
CV_WRAP DetectorParametersMCC(){
adaptiveThreshWinSizeMin=23;
adaptiveThreshWinSizeMax=153;
adaptiveThreshWinSizeStep=16;
adaptiveThreshConstant=7;
minContoursAreaRate=0.003;
minContoursArea=100;
confidenceThreshold=0.5;
minContourSolidity=0.9;
findCandidatesApproxPolyDPEpsMultiplier=0.05;
borderWidth=0;
B0factor=1.25f;
maxError=0.1f;
minContourPointsAllowed=4;
minContourLengthAllowed=100;
minInterContourDistance=100;
minInterCheckerDistance=10000;
minImageSize=1000;
minGroupSize=4;
}
/// minimum window size for adaptive thresholding before finding contours (default 23).
CV_PROP_RW int adaptiveThreshWinSizeMin;
/// maximum window size for adaptive thresholding before finding contours (default 153).
CV_PROP_RW int adaptiveThreshWinSizeMax;
/// increments from adaptiveThreshWinSizeMin to adaptiveThreshWinSizeMax during the thresholding (default 16).
CV_PROP_RW int adaptiveThreshWinSizeStep;
/// constant for adaptive thresholding before finding contours (default 7)
CV_PROP_RW double adaptiveThreshConstant;
/** @brief determine minimum area for marker contour to be detected
*
* This is defined as a rate respect to the area of the input image. Used only if neural network is used (default 0.03).
*/
CV_PROP_RW double minContoursAreaRate;
/** @brief determine minimum area for marker contour to be detected
*
* This is defined as the actual area. Used only if neural network is used (default 100).
*/
CV_PROP_RW double minContoursArea;
/// minimum confidence for a bounding box detected by neural network to classify as detection.(default 0.5) (0<=confidenceThreshold<=1)
CV_PROP_RW double confidenceThreshold;
/// minimum solidity of a contour for it be detected as a square in the chart. (default 0.9).
CV_PROP_RW double minContourSolidity;
/// multipler to be used in ApproxPolyDP function (default 0.05)
CV_PROP_RW double findCandidatesApproxPolyDPEpsMultiplier;
/// width of the padding used to pass the inital neural network detection in the succeeding system.(default 0)
CV_PROP_RW int borderWidth;
/// distance between two neighboring squares of the same chart as a ratio of the large dimension of a square (default 1.25).
CV_PROP_RW float B0factor;
/// maximum allowed error in the detection of a chart (default 0.1).
CV_PROP_RW float maxError;
/// minimum points in a detected contour (default 4).
CV_PROP_RW int minContourPointsAllowed;
/// minimum length of a contour (default 100).
CV_PROP_RW int minContourLengthAllowed;
/// minimum distance between two contours (default 100).
CV_PROP_RW int minInterContourDistance;
/// minimum distance between two checkers (default 10000).
CV_PROP_RW int minInterCheckerDistance;
/// minimum size of the smaller dimension of the image (default 1000).
CV_PROP_RW int minImageSize;
/// minimum number of squares in a chart that must be detected (default 4).
CV_PROP_RW int minGroupSize;
};
/** @brief A class to find the positions of the ColorCharts in the image.
*/
class CV_EXPORTS_W CCheckerDetector : public Algorithm
{
public:
/** @brief Find the ColorCharts in the given image.
*
* The found charts are not returned but instead stored in the
* detector, these can be accessed later on using getBestColorChecker()
* and getListColorChecker()
* @param image image in color space BGR
* @param regionsOfInterest regions of image to look for the chart, if
* it is empty, charts are looked for in the
* entire image
* @param nc number of charts in the image, if you don't know the exact
* then keeping this number high helps.
* @return true if atleast one chart is detected otherwise false
*/
CV_WRAP_AS(processWithROI) virtual bool
process(InputArray image, const std::vector<Rect> &regionsOfInterest,
const int nc = 1) = 0;
/** @brief Find the ColorCharts in the given image.
*
* Differs from the above one only in the arguments.
*
* This version searches for the chart in the full image.
*
* The found charts are not returned but instead stored in the
* detector, these can be accessed later on using getBestColorChecker()
* and getListColorChecker()
* @param image image in color space BGR
* @param nc number of charts in the image, if you don't know the exact
* then keeping this number high helps.
* @return true if atleast one chart is detected otherwise false
*/
CV_WRAP virtual bool
process(InputArray image, const int nc = 1) = 0;
/** @brief Get the best color checker. By the best it means the one
* detected with the highest confidence.
* @return checker A single colorchecker, if atleast one colorchecker
* was detected, 'nullptr' otherwise.
*/
CV_WRAP virtual Ptr<mcc::CChecker> getBestColorChecker() = 0;
/** @brief Get the list of all detected colorcheckers
* @return checkers vector of colorcheckers
*/
CV_WRAP virtual std::vector<Ptr<CChecker>> getListColorChecker() = 0;
/** @brief Returns the implementation of the CCheckerDetector.
*
*/
CV_WRAP static Ptr<CCheckerDetector> create();
/** @brief Set the net which will be used to find the approximate
* bounding boxes for the color charts. And returns the implementation of the CCheckerDetector.
*
* It is not necessary to use this, but this usually results in
* better detection rate.
*
* @param net the neural network, if the network in empty, then
* the function will return false.
*/
CV_WRAP static Ptr<CCheckerDetector> create(const dnn::Net &net);
/** @brief Draws the checker to the given image.
* @param img image in color space BGR
* @param checkers The checkers which will be drawn by this object.
* @param color The color by with which the squares of the checker
* will be drawn
* @param thickness The thickness with which the sqaures will be
* drawn
*/
CV_WRAP virtual void draw(std::vector<Ptr<CChecker>>& checkers, InputOutputArray img, const Scalar color = CV_RGB(0,250,0), const int thickness = 2) = 0;
/** @brief Gets the reference color for chart.
*/
CV_WRAP virtual Mat getRefColors() = 0;
/** @brief Sets the detection paramaters for mcc.
* @param params DetectorParametersMCC structure containing detection configuration parameters.
*/
CV_WRAP virtual void setDetectionParams(const DetectorParametersMCC &params) = 0;
/** @brief Sets the color chart type for MCC detection.
* @param chartType ColorChart enum specifying the type of color chart to detect.
*/
CV_WRAP virtual void setColorChartType(ColorChart chartType) = 0;
/** @brief Enables or disables the use of the neural network for detection.
* @param useDnn Boolean flag to indicate whether to use neural network (true) or not (false).
*/
CV_WRAP virtual void setUseDnnModel(bool useDnn) = 0;
CV_WRAP virtual bool getUseDnnModel() const = 0;
CV_WRAP virtual const DetectorParametersMCC& getDetectionParams() const = 0;
CV_WRAP virtual ColorChart getColorChartType() const = 0;
};
//! @} mcc
} // namespace mcc
} // namespace cv
#endif
+3
View File
@@ -19,6 +19,9 @@
"QRCodeDetectorAruco_Params": ["Params"],
"QRCodeDetectorAruco": ["QRCodeDetectorAruco", "decode", "detect", "detectAndDecode", "detectMulti", "decodeMulti", "detectAndDecodeMulti", "setDetectorParameters", "setArucoParameters"],
"barcode_BarcodeDetector": ["BarcodeDetector", "decode", "detect", "detectAndDecode", "detectMulti", "decodeMulti", "detectAndDecodeMulti", "decodeWithType", "detectAndDecodeWithType"],
"mcc_CheckerDetector": ["process", "getBestColorChecker", "getListColorChecker", "create", "draw", "getRefColors", "setDetectionParams", "getDetectionParams", "setColorChartType", "getColorChartType", "setUseDnnModel", "getUseDnnModel"],
"mcc_DetectorParameters": ["DetectorParametersMCC"],
"mcc_Checker": ["setTarget", "setBox", "setChartsRGB", "setChartsYCbCr", "setCost", "setCenter", "getTarget", "getBox", "getColorCharts", "getChartsRGB", "getChartsYCbCr", "getCost", "getCenter"],
"FaceDetectorYN": ["setInputSize", "getInputSize", "setScoreThreshold", "getScoreThreshold", "setNMSThreshold", "getNMSThreshold", "setTopK", "getTopK", "detect", "create"]
},
"namespace_prefix_override":
@@ -0,0 +1,4 @@
#include "opencv2/objdetect/mcc_checker_detector.hpp"
typedef std::vector<cv::Ptr<mcc::CChecker>> vector_Ptr_CChecker;
typedef dnn::Net dnn_Net;
+29
View File
@@ -0,0 +1,29 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "perf_precomp.hpp"
namespace opencv_test
{
namespace
{
using namespace std;
using namespace cv::mcc;
PERF_TEST(CV_mcc_perf, detect) {
string path = cvtest::findDataFile("cv/mcc/mcc_ccm_test.jpg");
Mat img = imread(path, IMREAD_COLOR);
Ptr<CCheckerDetector> detector = CCheckerDetector::create();
detector->setColorChartType(MCC24);
// detect MCC24 board
TEST_CYCLE() {
ASSERT_TRUE(detector->process(img, 1));
}
SANITY_CHECK_NOTHING();
}
} // namespace
} // namespace opencv_test
+180
View File
@@ -0,0 +1,180 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/*
* MIT License
*
* Copyright (c) 2018 Pedro Diamel Marrero Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "precomp.hpp"
#include "bound_min.hpp"
namespace cv
{
namespace mcc
{
CBoundMin::CBoundMin()
{
}
CBoundMin::~CBoundMin()
{
}
void CBoundMin::calculate()
{
corners.clear();
size_t N = chart.size();
if (!N)
return;
std::vector<Point2f> X(4 * N);
for (size_t i = 0; i < N; i++)
{
mcc::CChart cc = chart[i];
for (size_t j = 0; j < 4; j++)
{
X[i * 4 + j] = cc.corners[j];
}
}
// media
Point2f mu(0, 0);
for (size_t i = 0; i < 4 * N; i++)
mu += X[i];
mu /= (4 * (int)N);
for (size_t i = 0; i < 4 * N; i++)
X[i] -= mu;
// calculate all line
std::vector<Point3f> L;
L.resize(4 * N);
for (size_t i = 0; i < N; i++)
{
Point3f v0, v1, v2, v3;
v0.x = X[4 * i + 0].x;
v0.y = X[4 * i + 0].y;
v0.z = 1;
v1.x = X[4 * i + 1].x;
v1.y = X[4 * i + 1].y;
v1.z = 1;
v2.x = X[4 * i + 2].x;
v2.y = X[4 * i + 2].y;
v2.z = 1;
v3.x = X[4 * i + 3].x;
v3.y = X[4 * i + 3].y;
v3.z = 1;
L[4 * i + 0] = v0.cross(v1);
L[4 * i + 1] = v1.cross(v2);
L[4 * i + 2] = v2.cross(v3);
L[4 * i + 3] = v3.cross(v0);
}
// line convex hull
std::vector<int> dist;
dist.resize(4 * N);
Point2f n;
float d;
for (size_t i = 0; i < 4 * N; i++)
{
n.x = L[i].x;
n.y = L[i].y;
d = L[i].z;
int s = 0;
for (size_t j = 0; j < N; j++)
s += (X[j].dot(n) + d) <= 0;
dist[i] = s;
}
// sort
std::vector<int> idx;
std::vector<Point3f> Ls;
Ls.resize(4 * N);
mcc::sort(dist, idx);
for (size_t i = 0; i < 4 * N; i++)
Ls[i] = L[idx[i]];
std::vector<Point3f> Lc;
Lc.resize(4 * N);
Lc[0] = Ls[0];
Point3f ln;
int j, k = 0;
for (size_t i = 0; i < 4 * N; i++)
{
ln = Ls[i]; //current line
if (!validateLine(Lc, ln, k, j))
{
Lc[k] = ln;
k++;
}
else if ((abs(Lc[j].z) < abs(ln.z)) && (abs(dist[i] - dist[j]) < 2))
{
Lc[j] = ln;
}
if (k == 4 && abs(dist[i] - dist[k - 1]) > 2)
break;
}
if (k < 4)
return;
std::vector<float> thetas;
thetas.resize(4);
for (size_t i = 0; i < 4; i++)
thetas[i] = atan2(Lc[i].y / Lc[i].z, Lc[i].x / Lc[i].z);
sort(thetas, idx, false);
std::vector<Point3f> lines;
lines.resize(4);
for (size_t i = 0; i < 4; i++)
lines[i] = Lc[idx[i]];
Point3f Vcart;
Point2f Vhom;
std::vector<Point2f> V;
V.resize(4);
for (size_t i = 0; i < 4; i++)
{
j = (i + 1) % 4;
Vcart = lines[i].cross(lines[j]);
if (fabs(Vcart.z) <= 1e-6){
continue;
}
Vhom.x = Vcart.x / Vcart.z;
Vhom.y = Vcart.y / Vcart.z;
V[i] = Vhom + mu;
}
corners = V;
}
} // namespace mcc
} // namespace cv
+83
View File
@@ -0,0 +1,83 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/*
* MIT License
*
* Copyright (c) 2018 Pedro Diamel Marrero Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _MCC_BOUND_MIN_HPP
#define _MCC_BOUND_MIN_HPP
#include "charts.hpp"
namespace cv
{
namespace mcc
{
class CBoundMin
{
public:
CBoundMin();
~CBoundMin();
void setCharts(const std::vector<CChart> &chartIn) { chart = chartIn; }
void getCorners(std::vector<Point2f> &cornersOut) { cornersOut = corners; }
void calculate();
private:
std::vector<CChart> chart;
std::vector<Point2f> corners;
private:
bool validateLine(const std::vector<Point3f> &Lc, Point3f ln,
int k, int &j)
{
double theta;
Point2d v0, v1;
for (j = 0; j < k; j++)
{
v0.x = Lc[j].x;
v0.y = Lc[j].y;
v1.x = ln.x;
v1.y = ln.y;
theta = v0.dot(v1) / (norm(v0) * norm(v1));
theta = acos(theta);
if (theta < 0.5)
return true;
}
return false;
}
};
} // namespace mcc
} // namespace cv
#endif //_MCC_BOUND_MIN_HPP
+96
View File
@@ -0,0 +1,96 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/*
* MIT License
*
* Copyright (c) 2018 Pedro Diamel Marrero Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "precomp.hpp"
#include "charts.hpp"
namespace cv
{
namespace mcc
{
CChart::CChart()
: perimetro(0), area(0), large_side(0)
{
}
CChart::~CChart()
{
}
void CChart::
setCorners(std::vector<Point2f> p)
{
Point v1, v2;
if (p.empty())
return;
// copy
corners = p;
// Sort the corners in anti-clockwise order
polyanticlockwise(corners);
// Properties
area = contourArea(corners);
perimetro = perimeter(corners);
center = mace_center(corners);
v1 = corners[2] - corners[0];
v2 = corners[3] - corners[1];
large_side = std::max(norm(v1), norm(v2));
}
//////////////////////////////////////////////////////////////////////////////////////////////
CChartDraw::
CChartDraw(CChart &pChart, InputOutputArray image)
: m_pChart(pChart), m_image(image.getMat())
{
}
void CChartDraw::
drawContour(Scalar color /*= CV_RGB(0, 250, 0)*/) const
{
//Draw lines
int thickness = 2;
line(m_image, (m_pChart).corners[0], (m_pChart).corners[1], color, thickness, LINE_AA);
line(m_image, (m_pChart).corners[1], (m_pChart).corners[2], color, thickness, LINE_AA);
line(m_image, (m_pChart).corners[2], (m_pChart).corners[3], color, thickness, LINE_AA);
line(m_image, (m_pChart).corners[3], (m_pChart).corners[0], color, thickness, LINE_AA);
}
void CChartDraw::
drawCenter(Scalar color /*= CV_RGB(0, 0, 255)*/) const
{
int radius = 3;
int thickness = 2;
circle(m_image, (m_pChart).center, radius, color, thickness);
}
} // namespace mcc
} // namespace cv
+90
View File
@@ -0,0 +1,90 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/*
* MIT License
*
* Copyright (c) 2018 Pedro Diamel Marrero Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _MCC_CHARTS_HPP
#define _MCC_CHARTS_HPP
namespace cv
{
namespace mcc
{
/** @brief Chart model
*
* .--------. <- px,py
* | | one chart for checker color
* | RGB |
* | Lab |
* | |
* .--------.
*
* @author Pedro Marrero Fernndez
*/
class CChart
{
public:
CChart();
~CChart();
/** @brief set corners
*@param p[in] new corners
*/
void setCorners(std::vector<Point2f> p);
public:
std::vector<Point2f> corners;
Point2f center;
double perimetro;
double area;
double large_side;
};
/** @brief Chart draw */
class CChartDraw
{
public:
/** @brief contructor */
CChartDraw(CChart &pChart, InputOutputArray image);
/** @brief draw the chart contour over the image */
void drawContour(Scalar color = CV_RGB(0, 250, 0)) const;
/** @brief draw the chart center over the image */
void drawCenter(Scalar color = CV_RGB(0, 0, 255)) const;
private:
CChart &m_pChart;
Mat m_image;
};
} // namespace mcc
} // namespace cv
#endif //_MCC_CHARTS_HPP
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,207 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/*
* MIT License
*
* Copyright (c) 2018 Pedro Diamel Marrero Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _MCC_CHECKER_DETECTOR_HPP
#define _MCC_CHECKER_DETECTOR_HPP
#include "opencv2/objdetect.hpp"
#include "charts.hpp"
namespace cv
{
namespace mcc
{
class CCheckerDetectorImpl : public CCheckerDetector
{
typedef std::vector<Point> PointsVector;
typedef std::vector<PointsVector> ContoursVector;
public:
CCheckerDetectorImpl();
CCheckerDetectorImpl(const dnn::Net& _net){
net = _net;
}
virtual ~CCheckerDetectorImpl();
bool process(InputArray image, const std::vector<Rect> &regionsOfInterest,
const int nc = 1) CV_OVERRIDE;
bool process(InputArray image, const int nc = 1) CV_OVERRIDE;
Ptr<CChecker> getBestColorChecker() CV_OVERRIDE
{
if (m_checkers.size())
return m_checkers[0];
return nullptr;
}
std::vector<Ptr<CChecker>> getListColorChecker() CV_OVERRIDE
{
return m_checkers;
}
virtual Mat getRefColors() CV_OVERRIDE;
virtual void setDetectionParams(const DetectorParametersMCC &params) CV_OVERRIDE;
virtual void setColorChartType(ColorChart chartType) CV_OVERRIDE;
virtual void setUseDnnModel(bool useDnn) CV_OVERRIDE;
virtual bool getUseDnnModel() const CV_OVERRIDE;
virtual const DetectorParametersMCC& getDetectionParams() const CV_OVERRIDE;
virtual ColorChart getColorChartType() const CV_OVERRIDE;
virtual void draw(std::vector<Ptr<CChecker>>& checkers, InputOutputArray img, const Scalar color = CV_RGB(0,250,0), const int thickness = 2) CV_OVERRIDE;
protected: // methods pipeline
bool _no_net_process(InputArray image, const int nc, std::vector<Rect> regionsOfInterest);
/// prepareImage
/** @brief Prepare Image
* @param bgrMat image in color space BGR
* @param grayOut gray scale
* @param bgrOut rescale image
* @param aspOut aspect ratio
* @param max_size rescale factor in max dim
*/
virtual void
prepareImage(InputArray bgr, OutputArray grayOut, OutputArray bgrOut, float &aspOut) const;
/// performThreshold
/** @brief Adaptative threshold
* @param grayscaleImg gray scale image
* @param thresholdImg binary image
* @param wndx, wndy windows size
* @param step
*/
virtual void
performThreshold(InputArray grayscaleImg, OutputArrayOfArrays thresholdImg) const;
/// findContours
/** @brief find contour in the image
* @param srcImg binary imagen
* @param contours
* @param minContourPointsAllowed
*/
virtual void
findContours(InputArray srcImg, ContoursVector &contours) const;
/// findCandidates
/** @brief find posibel candidates
* @param contours
* @param detectedCharts
* @param minContourLengthAllowed
*/
virtual void
findCandidates(const ContoursVector &contours, std::vector<CChart> &detectedCharts);
/// clustersAnalysis
/** @brief clusters charts analysis
* @param detectedCharts
* @param groups
*/
virtual void
clustersAnalysis(const std::vector<CChart> &detectedCharts, std::vector<int> &groups);
/// checkerRecognize
/** @brief checker color recognition
* @param img
* @param detectedCharts
* @param G
* @param colorChartsOut
*/
virtual void
checkerRecognize(InputArray img, const std::vector<CChart> &detectedCharts, const std::vector<int> &G,
std::vector<std::vector<Point2f>> &colorChartsOut);
/// checkerAnalysis
/** @brief evaluate checker
* @param img
* @param img_org
* @param colorCharts
* @param checker
* @param asp
*/
virtual void
checkerAnalysis(InputArray img_rgb_f, const unsigned int nc,
const std::vector<std::vector<Point2f>> &colorCharts,
std::vector<Ptr<CChecker>> &checkers, float asp,
const Mat &img_rgb_org,
const Mat &img_ycbcr_org,
std::vector<Mat> &rgb_planes,
std::vector<Mat> &ycbcr_planes);
virtual void
removeTooCloseDetections();
protected:
std::vector<Ptr<CChecker>> m_checkers;
dnn::Net net;
DetectorParametersMCC m_params = DetectorParametersMCC();
ColorChart m_chartType;
bool m_useDnn = true;
private: // methods aux
void get_subbox_chart_physical(
const std::vector<Point2f> &points,
std::vector<Point2f> &chartPhy);
void reduce_array(
const std::vector<float> &x,
std::vector<float> &x_new,
float tol);
void transform_points_inverse(
InputArray T,
const std::vector<Point2f> &X,
std::vector<Point2f> &Xt);
void get_profile(
const std::vector<Point2f> &ibox,
OutputArray charts_rgb,
OutputArray charts_ycbcr,
InputArray im_rgb,
InputArray im_ycbcr,
std::vector<Mat> &rgb_planes,
std::vector<Mat> &ycbcr_planes);
/** @brief cost function
* e(p) = ||f(p)||^2 = \sum_k (mu_{k,p}*r_k')/||mu_{k,p}||||r_k|| + ...
* + \sum_k || \sigma_{k,p} ||^2
*/
float cost_function(InputArray img, InputOutputArray mask, InputArray lab,
const std::vector<Point2f> &ibox);
};
} // namespace mcc
} // namespace cv
#endif //_MCC_CHECKER_DETECTOR_HPP
+487
View File
@@ -0,0 +1,487 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/*
* MIT License
*
* Copyright (c) 2018 Pedro Diamel Marrero Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "precomp.hpp"
#include "checker_model.hpp"
#include "dictionary.hpp"
namespace cv
{
namespace mcc
{
///////////////////////////////////////////////////////////////////////////////
/// CChartModel
CChartModel::CChartModel(const ColorChart chartType)
{
switch (chartType)
{
case MCC24: //Standard
size = Size2i(4, 6);
boxsize = Size2f(11.25, 16.75);
box.resize(4);
box[0] = Point2f(0.00, 0.00);
box[1] = Point2f(16.75, 0.00);
box[2] = Point2f(16.75, 11.25);
box[3] = Point2f(0.00, 11.25);
cellchart.assign(CChartClassicModelCellchart, CChartClassicModelCellchart + 4 * 24);
center.assign(CChartClassicModelCenter, CChartClassicModelCenter + 24);
chart.resize(size.area(), std::vector<float>(9));
for(int color = 0 ; color < (int)chart.size() ; color++)
chart[color].assign(CChartClassicModelColors[color] , CChartClassicModelColors[color] + 9 );
break;
case SG140: //DigitalSG
size = Size2i(10, 14);
boxsize = Size2f(27.75, 38.75);
box.resize(4);
box[0] = Point2f(0.00, 0.00);
box[1] = Point2f(38.75, 0.00);
box[2] = Point2f(38.75, 27.75);
box[3] = Point2f(0.00, 27.75);
cellchart.assign(CChartDigitalSGCellchart, CChartDigitalSGCellchart + 4 * 140);
center.assign(CChartDigitalSGCenter, CChartDigitalSGCenter + 140);
chart.resize(size.area(), std::vector<float>(9));
for(int color = 0 ; color < (int)chart.size() ; color++)
chart[color].assign(CChartDigitalSGColors[color] , CChartDigitalSGColors[color] + 9 );
break;
case VINYL18: //Vinyl
size = Size2i(3, 6);
boxsize = Size2f(12.50, 18.25);
box.resize(4);
box[0] = Point2f(0.00, 0.00);
box[1] = Point2f(18.25, 0.00);
box[2] = Point2f(18.25, 12.50);
box[3] = Point2f(0.00, 12.50);
cellchart.assign(CChartVinylCellchart, CChartVinylCellchart + 4 * 18);
center.assign(CChartVinylCenter, CChartVinylCenter + 18);
chart.resize(size.area(), std::vector<float>(9));
for(int color = 0 ; color < (int)chart.size() ; color++)
chart[color].assign(CChartVinylColors[color] , CChartVinylColors[color] + 9 );
break;
}
}
CChartModel::~CChartModel()
{
}
bool CChartModel::
evaluate(const SUBCCMModel &subModel, int &offset, int &iTheta, float &error)
{
float tError;
int tTheta, tOffset;
error = INFINITY;
bool beval = false;
// para todas las orientaciones
// min_{ theta,dt } | CC_e - CC |
for (tTheta = 0; tTheta < 8; tTheta++)
{
if (match(subModel, tTheta, tError, tOffset) && tError < error)
{
error = tError;
iTheta = tTheta;
offset = tOffset;
beval = true;
}
}
return beval;
}
void CChartModel::
copyToColorMat(OutputArray lab, int cs)
{
size_t N, M, k;
N = size.width;
M = size.height;
Mat im_lab_org((int)N, (int)M, CV_32FC3);
int type_color = 3 * cs;
k = 0;
for (size_t i = 0; i < N; i++)
{
for (size_t j = 0; j < M; j++)
{
Vec3f &lab_values = im_lab_org.at<Vec3f>((int)i, (int)j);
lab_values[0] = chart[k][type_color + 0];
lab_values[1] = chart[k][type_color + 1];
lab_values[2] = chart[k][type_color + 2];
k++;
}
}
lab.assign(im_lab_org);
}
void mcc::CChartModel::
rotate90()
{
size = Size2i(size.height, size.width);
//the matrix is roated clockwise 90 degree, so first row will become last column, second row second last column and so on
//doing this inplace will make the code a bit hard to read, so creating a temporary array
std::vector<Point2f> _cellchart(cellchart.size());
std::vector<Point2f> _center(center.size());
int k = 0;
for (int i = 0; i < size.width; i++)
{
for (int j = 0; j < size.height; j++)
{
//k contains the new coordintes,
int old_i = size.height - j - 1;
int old_j = i;
int old_k = (old_i)*size.width + old_j;
_cellchart[4 * k + 0] = cellchart[4 * old_k + 3];
_cellchart[4 * k + 1] = cellchart[4 * old_k + 0];
_cellchart[4 * k + 2] = cellchart[4 * old_k + 1];
_cellchart[4 * k + 3] = cellchart[4 * old_k + 2];
// center
_center[k] = center[old_k];
k++;
}
}
cellchart = _cellchart;
center = _center;
boxsize = Size2f(boxsize.height, boxsize.width);
}
void mcc::CChartModel::
flip()
{
std::vector<Point2f> _cellchart(cellchart.size());
std::vector<Point2f> _center(center.size());
int k = 0;
for (int i = 0; i < size.width; i++)
{
for (int j = 0; j < size.height; j++)
{
//k contains the new coordintes,
int old_i = i;
int old_j = size.height - j - 1;
int old_k = (old_i)*size.height + old_j;
_cellchart[4 * k + 0] = cellchart[4 * old_k + 1];
_cellchart[4 * k + 1] = cellchart[4 * old_k + 0];
_cellchart[4 * k + 2] = cellchart[4 * old_k + 3];
_cellchart[4 * k + 3] = cellchart[4 * old_k + 2];
// center
_center[k] = center[old_k];
k++;
}
}
cellchart = _cellchart;
center = _center;
}
float CChartModel::
dist_color_lab(InputArray lab1, InputArray lab2)
{
int N = lab1.rows();
float dist = 0, dist_i;
Mat _lab1 = lab1.getMat(), _lab2 = lab2.getMat();
for (int i = 0; i < N; i++)
{
Vec3f v1 = _lab1.at<Vec3f>(i, 0);
Vec3f v2 = _lab2.at<Vec3f>(i, 0);
// v1[0] = 1;
// v2[0] = 1; // L <- 0
// euclidean
Vec3f v = v1 - v2;
dist_i = v.dot(v);
dist += sqrt(dist_i);
// cosine
//float costh = v1.dot(v2) / (norm(v1)*norm(v2));
//dist += 1 - (1 + costh) / 2;
}
dist /= N;
return dist;
}
bool CChartModel::
match(const SUBCCMModel &subModel, int iTheta, float &error, int &ierror)
{
size_t N, M, k;
N = size.width;
M = size.height;
Mat im_lab_org((int)N, (int)M, CV_32FC3);
int type_color = 3;
k = 0;
for (size_t i = 0; i < N; i++)
{
for (size_t j = 0; j < M; j++)
{
Vec3f &lab = im_lab_org.at<Vec3f>((int)i, (int)j);
lab[0] = chart[k][type_color + 0];
lab[1] = chart[k][type_color + 1];
lab[2] = chart[k][type_color + 2];
k++;
}
}
rot90(im_lab_org, iTheta);
N = im_lab_org.rows;
M = im_lab_org.cols;
size_t n, m;
n = subModel.color_size.height;
m = subModel.color_size.width;
// boundary condition
if (N < n || M < m)
return false;
// rgb to La*b*
Mat rgb_est = subModel.sub_chart;
Mat lab_est;
cvtColor(rgb_est, lab_est, COLOR_BGR2Lab);
size_t nN, mM;
nN = N - n + 1;
mM = M - m + 1;
std::vector<float> lEcm(nN * mM);
k = 0;
for (size_t i = 0; i < nN; i++)
{
for (size_t j = 0; j < mM; j++)
{
Mat lab_curr, lab_roi;
lab_roi = im_lab_org(Rect((int)j, (int)i, (int)m, (int)n));
lab_roi.copyTo(lab_curr);
lab_curr = lab_curr.t();
lab_curr = lab_curr.reshape(3, (int)n * (int)m);
// Mean squared error
// ECM = 1 / N sum_i(Y - Yp) ^ 2
lEcm[k] = dist_color_lab(lab_curr, lab_est) / (M * N);
k++;
}
}
// minimo
error = lEcm[0];
ierror = 0;
for (int i = 1; i < (int)lEcm.size(); i++)
if (error > lEcm[i])
{
error = lEcm[i];
ierror = i;
}
return true;
}
void CChartModel::
rot90(InputOutputArray mat, int itheta)
{
//1=CW, 2=CCW, 3=180
switch (itheta)
{
case 1: //transpose+flip(1)=CW
transpose(mat, mat);
cv::flip(mat, mat, 1);
break;
case 2: //flip(-1)=180
cv::flip(mat, mat, -1);
break;
case 3: //transpose+flip(0)=CCW
transpose(mat, mat);
cv::flip(mat, mat, 0);
break;
//flipped images start here
case 4: //flip(1)=no rotation, just flipped
cv::flip(mat, mat, 1);
break;
case 5: //flip(1)+transpose + flip(1)=CW
cv::flip(mat, mat, 1);
transpose(mat, mat);
cv::flip(mat, mat, 1);
break;
case 6: //flip(1)+flip(-1)=180
cv::flip(mat, mat, 1);
cv::flip(mat, mat, -1);
break;
case 7: //flip(1)+transpose+flip(0)=CCW
cv::flip(mat, mat, 1);
transpose(mat, mat);
cv::flip(mat, mat, 0);
break;
}
}
//////////////////////////////////////////////////////////////////////////////////////////////
// // CChecker
Ptr<CChecker> CChecker::create()
{
return makePtr<CCheckerImpl>();
}
void CCheckerImpl::setTarget(ColorChart _target)
{
target = _target;
}
void CCheckerImpl::setBox(std::vector<Point2f> _box)
{
box = _box;
}
void CCheckerImpl::setChartsRGB(Mat _chartsRGB)
{
chartsRGB = _chartsRGB;
}
void CCheckerImpl::setChartsYCbCr(Mat _chartsYCbCr)
{
chartsYCbCr = _chartsYCbCr;
}
void CCheckerImpl::setCost(float _cost)
{
cost = _cost;
}
void CCheckerImpl::setCenter(Point2f _center)
{
center = _center;
}
ColorChart CCheckerImpl::getTarget()
{
return target;
}
std::vector<Point2f> CCheckerImpl::getBox()
{
return box;
}
std::vector<Point2f> CCheckerImpl::getColorCharts()
{
// color chart classic model
CChartModel cccm(getTarget());
Mat lab;
size_t N;
std::vector<Point2f> fbox = cccm.box;
std::vector<Point2f> cellchart = cccm.cellchart;
std::vector<Point2f> charts(cellchart.size());
// tranformation
Matx33f ccT = getPerspectiveTransform(fbox, getBox());
std::vector<Point2f> bch(4), bcht(4);
N = cellchart.size() / 4;
for (size_t i = 0, k; i < N; i++)
{
k = 4 * i;
for (size_t j = 0ull; j < 4ull; j++)
bch[j] = cellchart[k + j];
polyanticlockwise(bch);
transform_points_forward(ccT, bch, bcht);
Point2f c(0, 0);
for (size_t j = 0; j < 4; j++)
c += bcht[j];
c /= 4;
for (size_t j = 0ull; j < 4ull; j++)
charts[k+j] = ((bcht[j] - c) * 0.50) + c;
}
return charts;
}
Mat CCheckerImpl::getChartsRGB(bool getStats /* = true */)
{
if (!getStats){
Mat src = chartsRGB.col(1).clone().reshape(3, chartsRGB.rows/3);
return src;
}
return chartsRGB;
}
Mat CCheckerImpl::getChartsYCbCr()
{
return chartsYCbCr;
}
float CCheckerImpl::getCost()
{
return cost;
}
Point2f CCheckerImpl::getCenter()
{
return center;
}
void transform_points_forward(const Matx33f& T, const std::vector<Point2f> &X, std::vector<Point2f> &Xt)
{
size_t N = X.size();
if (Xt.size() != N)
Xt.resize(N);
std::fill(Xt.begin(), Xt.end(), Point2f(0.f, 0.f));
if (N == 0)
return;
Matx31f p, xt;
Point2f pt;
for (size_t i = 0; i < N; i++)
{
p(0, 0) = X[i].x;
p(1, 0) = X[i].y;
p(2, 0) = 1;
xt = T * p;
pt.x = xt(0, 0) / xt(2, 0);
pt.y = xt(1, 0) / xt(2, 0);
Xt[i] = pt;
}
}
} // namespace mcc
} // namespace cv
+161
View File
@@ -0,0 +1,161 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/*
* MIT License
*
* Copyright (c) 2018 Pedro Diamel Marrero Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _MCC_CHECKER_MODEL_HPP
#define _MCC_CHECKER_MODEL_HPP
namespace cv
{
namespace mcc
{
//! @addtogroup mcc
//! @{
/** CChartModel
*
* @brief Class for handing the different chart models.
*
* This class contains the variables and functions which are specific
* to a given chart type and will be used for it detections.
*/
class CChartModel
{
public:
/** SUBCCMModel
*
* @brief Information about a continuous subregion of the chart.
*
* Usually not all the cells of the chart can be detected by the
* detector. This submodel contains the information about the
* detected squares.
*/
typedef struct
_SUBCCMModel
{
Mat sub_chart;
Size2i color_size;
std::vector<Point2f> centers;
} SUBCCMModel;
public:
CChartModel(const ColorChart chartType);
~CChartModel();
/** @brief evaluate submodel in this checker type*/
bool evaluate(const SUBCCMModel &subModel, int &offset, int &iTheta, float &error);
// function utils
void copyToColorMat(OutputArray lab, int cs = 0);
void rotate90();
void flip();
public:
// Cie L*a*b* values use illuminant D50 2 degree observer sRGB values for
// for iluminante D65.
Size2i size;
Size2f boxsize;
std::vector<Point2f> box;
std::vector<Point2f> cellchart;
std::vector<Point2f> center;
std::vector<std::vector<float>> chart;
protected:
/** \brief match checker color
* \param[in] subModel sub-checker
* \param[in] iTheta angle
* \param[out] error
* \param[out] ierror
* \return state
*/
bool match(const SUBCCMModel &subModel, int iTheta, float &error, int &ierror);
/** \brief euclidian dist L2 for Lab space
* \note
* \f$ \sum_i \sqrt (\sum_k (ab1-ab2)_k.^2) \f$
* \param[in] lab1
* \param[in] lab2
* \return distance
*/
float dist_color_lab(InputArray lab1, InputArray lab2);
/** \brief rotate matrix 90 degree */
void rot90(InputOutputArray mat, int itheta);
};
/** CChecker
*
* \brief checker model
* \author Pedro Marrero Fernandez
*
*/
class CCheckerImpl : public CChecker
{
public:
public:
CCheckerImpl() {}
~CCheckerImpl() {}
void setTarget(ColorChart _target) CV_OVERRIDE;
void setBox(std::vector<Point2f> _box) CV_OVERRIDE;
void setChartsRGB(Mat _chartsRGB) CV_OVERRIDE;
void setChartsYCbCr(Mat _chartsYCbCr) CV_OVERRIDE;
void setCost(float _cost) CV_OVERRIDE;
void setCenter(Point2f _center) CV_OVERRIDE;
ColorChart getTarget() CV_OVERRIDE;
std::vector<Point2f> getBox() CV_OVERRIDE;
std::vector<Point2f> getColorCharts() CV_OVERRIDE;
Mat getChartsRGB(bool getStats = true) CV_OVERRIDE;
Mat getChartsYCbCr() CV_OVERRIDE;
float getCost() CV_OVERRIDE;
Point2f getCenter() CV_OVERRIDE;
private:
ColorChart target; ///< type of checkercolor
std::vector<Point2f> box; ///< positions of the corners
Mat chartsRGB; ///< charts profile in rgb color space
Mat chartsYCbCr; ///< charts profile in YCbCr color space
float cost; ///< cost to aproximate
Point2f center; ///< center of the chart.
};
// @}
void transform_points_forward(const Matx33f& T, const std::vector<Point2f> &X, std::vector<Point2f> &Xt);
} // namespace mcc
} // namespace cv
#endif //_MCC_CHECKER_MODEL_HPP
+111
View File
@@ -0,0 +1,111 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/*
* MIT License
*
* Copyright (c) 2018 Pedro Diamel Marrero Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "precomp.hpp"
#include "common.hpp"
namespace cv
{
namespace mcc
{
Rect poly2mask(const std::vector<Point2f> &poly, Size size, InputOutputArray mask)
{
// Create Polygon from vertices
std::vector<Point> roi_poly;
approxPolyDP(poly, roi_poly, 1.0, true);
Rect roi = boundingRect(roi_poly);
// Fill polygon white
fillConvexPoly(mask, &roi_poly[0], (int)roi_poly.size(), 1, 8, 0);
roi &= Rect(0, 0, size.width, size.height);
if (roi.empty())
roi = Rect(0, 0, 1, 1);
return roi;
}
float perimeter(const std::vector<Point2f> &ps)
{
float sum = 0, dx, dy;
for (size_t i = 0; i < ps.size(); i++)
{
int i2 = (i + 1) % (int)ps.size();
dx = ps[i].x - ps[i2].x;
dy = ps[i].y - ps[i2].y;
sum += sqrt(dx * dx + dy * dy);
}
return sum;
}
Point2f
mace_center(const std::vector<Point2f> &ps)
{
Point2f center;
int n;
center = Point2f(0);
n = (int)ps.size();
for (int i = 0; i < n; i++)
center += ps[i];
center /= n;
return center;
}
void polyanticlockwise(std::vector<Point2f> &points)
{
// Sort the points in anti-clockwise order
// Trace a line between the first and second point.
// If the third point is at the right side, then the points are anti-clockwise
Point2f v1 = points[1] - points[0];
Point2f v2 = points[2] - points[0];
//if the third point is in the left side, then sort in anti-clockwise order
if ((v1.x * v2.y) - (v1.y * v2.x) < 0.0)
std::swap(points[1], points[3]);
}
void polyclockwise(std::vector<Point2f> &points)
{
// Sort the points in clockwise order
// Trace a line between the first and second point.
// If the third point is at the right side, then the points are clockwise
Point2f v1 = points[1] - points[0];
Point2f v2 = points[2] - points[0];
//if the third point is in the left side, then sort in clockwise order
if ((v1.x * v2.y) - (v1.y * v2.x) > 0.0)
std::swap(points[1], points[3]);
}
} // namespace mcc
} // namespace cv
+133
View File
@@ -0,0 +1,133 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/*
* MIT License
*
* Copyright (c) 2018 Pedro Diamel Marrero Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _MCC_COMMON_HPP
#define _MCC_COMMON_HPP
namespace cv
{
namespace mcc
{
Rect poly2mask(const std::vector<Point2f> &poly, Size size, InputOutputArray mask);
template <typename T>
void circshift(std::vector<T> &A, int shiff)
{
if (A.empty() || shiff < 1)
return;
int n = A.size();
if (shiff >= n)
return;
std::vector<T> Tmp(n);
for (int i = shiff; i < n + shiff; i++)
Tmp[(i % n)] = A[i - shiff];
A = Tmp;
}
float perimeter(const std::vector<Point2f> &ps);
Point2f mace_center(const std::vector<Point2f> &ps);
template <typename T>
void unique(const std::vector<T> &A, std::vector<T> &U)
{
int n = (int)A.size();
std::vector<T> Tm = A;
std::sort(Tm.begin(), Tm.end());
U.clear();
U.push_back(Tm[0]);
for (int i = 1; i < n; i++)
if (Tm[i] != Tm[i - 1])
U.push_back(Tm[i]);
}
void polyanticlockwise(std::vector<Point2f> &points);
void polyclockwise(std::vector<Point2f> &points);
// Does lexical cast of the input argument to string
template <typename T>
std::string ToString(const T &value)
{
std::ostringstream stream;
stream << value;
return stream.str();
}
template <typename T>
void change(T &a, T &b)
{
T c = a;
a = b;
b = c;
}
template <typename T>
void sort(std::vector<T> &A, std::vector<int> &idx, bool ord = true)
{
size_t N = A.size();
if (N == 0)
return;
idx.clear();
idx.resize(N);
for (size_t i = 0; i < N; i++)
idx[i] = (int)i;
for (size_t i = 0; i < N - 1; i++)
{
size_t k = i;
T valor = A[i];
for (size_t j = i + 1; j < N; j++)
{
if ((A[j] < valor && ord) || (A[j] > valor && !ord))
{
valor = A[j];
k = j;
}
}
if (k == i)
continue;
change(A[i], A[k]);
change(idx[i], idx[k]);
}
}
} // namespace mcc
} // namespace cv
#endif //_MCC_COMMON_HPP
+68
View File
@@ -0,0 +1,68 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/*
* MIT License
*
* Copyright (c) 2018 Pedro Diamel Marrero Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "precomp.hpp"
#include "debug.hpp"
#ifdef MCC_DEBUG
#include <opencv2/highgui.hpp>
namespace cv
{
namespace mcc
{
Scalar randomcolor(RNG &rng)
{
int icolor = (unsigned)rng;
return Scalar(icolor & 255, (icolor >> 8) & 255, (icolor >> 16) & 255);
}
void imshow_250xN(const std::string &name_, InputArray patch)
{
Mat bigpatch;
Size size = patch.size();
float asp = (float)size.height / size.width;
int new_size = 550;
resize(patch, bigpatch, Size((int)new_size, int(new_size * asp)));
imshow(name_, bigpatch);
}
void showAndSave(std::string name, InputArray m, std::string path)
{
imshow_250xN(name, m);
imwrite(path + "/" + name + ".png", m);
if (waitKey(0) == 'q')
return;
}
} // namespace mcc
} // namespace cv
#endif
+50
View File
@@ -0,0 +1,50 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/*
* MIT License
*
* Copyright (c) 2018 Pedro Diamel Marrero Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _MCC_DEBUG_HPP
#define _MCC_DEBUG_HPP
#include "opencv2/objdetect/mcc_checker_detector.hpp"
#ifdef MCC_DEBUG
namespace cv
{
namespace mcc
{
Scalar randomcolor(RNG &rng);
void imshow_250xN(const std::string &name_, InputArray patch);
void showAndSave(std::string name, InputArray m, std::string path);
} // namespace mcc
} // namespace cv
#endif
#endif //_MCC_DEBUG_HPP
File diff suppressed because it is too large Load Diff
+139
View File
@@ -0,0 +1,139 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/*
* MIT License
*
* Copyright (c) 2018 Pedro Diamel Marrero Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "precomp.hpp"
#include "graph_cluster.hpp"
namespace cv
{
namespace mcc
{
CB0cluster::CB0cluster()
{
}
CB0cluster::~CB0cluster()
{
}
void CB0cluster::
group()
{
size_t n = X.size();
G.clear();
G.resize(n);
for (int i = 0; i < (int)n - 1; i++)
{
std::vector<double> Y;
Y.clear();
Y.resize(n - i);
Y[0] = 0;
// 1. group similar blobs
double dist, w, y;
for (int j = i + 1, k = 1; j < (int)n; j++, k++)
{
//dist(X_i,X_j)
dist = norm(X[i] - X[j]);
//heuristic to combine two sub charts, This is pretty ugly at the moment,
//Looking for somthing better
w = min(abs(W[i] - W[j]) / (W[i] + W[j]),
abs(max(W[i], W[j]) - 24 / 11.0f * min(W[i], W[j])) / (max(W[i], W[j]) + 24 / 11.0f * min(W[i], W[j])));
w = (w < 0.1);
y = w * dist;
Y[k] = (y < B0[i]) * y;
;
}
if (!G[i])
G[i] = i + 1;
std::vector<int> pos_b0;
find(Y, pos_b0);
size_t m = pos_b0.size();
if (!m)
continue;
std::vector<int> pos_nz, pos_z;
for (int j = 0; j < (int)m; j++)
{
pos_b0[j] = pos_b0[j] + i;
if (G[pos_b0[j]])
pos_nz.push_back(j);
else
pos_z.push_back(j);
}
for (int j = 0; j < (int)pos_z.size(); j++)
{
pos_z[j] = pos_b0[pos_z[j]];
G[pos_z[j]] = G[i];
}
if (!pos_nz.size())
continue;
std::vector<int> g;
for (size_t j = 0; j < pos_nz.size(); j++)
{
pos_nz[j] = pos_b0[pos_nz[j]];
g.push_back(G[pos_nz[j]]);
}
unique(g, g);
for (size_t k = 0; k < g.size(); k++)
{
int gk = g[k];
for (size_t j = 0; j < G.size(); j++)
if (G[j] == gk)
G[j] = G[i];
}
}
if (!G[n - 1])
G[n - 1] = (int)n;
std::vector<int> S;
S = G;
unique(S, S);
for (int k = 0; k < (int)S.size(); k++)
{
int gk = S[k];
for (int j = 0; j < (int)G.size(); j++)
if (G[j] == gk)
G[j] = k;
}
}
} // namespace mcc
} // namespace cv
@@ -0,0 +1,74 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/*
* MIT License
*
* Copyright (c) 2018 Pedro Diamel Marrero Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _MCC_GRAPH_CLUSTERS_HPP
#define _MCC_GRAPH_CLUSTERS_HPP
namespace cv
{
namespace mcc
{
class CB0cluster
{
public:
CB0cluster();
~CB0cluster();
inline void setVertex(const std::vector<Point> &V) { X = V; }
inline void setB0(const std::vector<double> &b0) { B0 = b0; }
inline void setWeight(const std::vector<double> &Weight) { W = Weight; }
void group();
void getGroup(std::vector<int> &g) { g = G; }
private:
//entrada
std::vector<Point> X;
std::vector<double> B0;
std::vector<double> W;
//salida
std::vector<int> G;
private:
template <typename T>
void find(const std::vector<T> &A, std::vector<int> &indx)
{
indx.clear();
for (int i = 0; i < (int)A.size(); i++)
if (A[i])
indx.push_back(i);
}
};
} // namespace mcc
} // namespace cv
#endif //_MCC_GRAPH_CLUSTERS_HPP
+46
View File
@@ -0,0 +1,46 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/*
* MIT License
*
* Copyright (c) 2018 Pedro Diamel Marrero Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _MCC_PRECOMP_HPP
#define _MCC_PRECOMP_HPP
#include <limits>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/3d.hpp>
#include <opencv2/dnn.hpp>
#include <vector>
#include <string>
#include "opencv2/objdetect.hpp"
#include "common.hpp"
#endif //_MCC_PRECOMP_HPP
@@ -0,0 +1,98 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/*
* MIT License
*
* Copyright (c) 2018 Pedro Diamel Marrero Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "wiener_filter.hpp"
namespace cv
{
namespace mcc
{
CWienerFilter::CWienerFilter()
{
}
CWienerFilter::~CWienerFilter()
{
}
void CWienerFilter::
wiener2(InputArray _src, OutputArray _dst, int szWindowX, int szWindowY)
{
CV_Assert(szWindowX > 0 && szWindowY > 0);
Mat src = _src.getMat();
int nRows;
int nCols;
Scalar v = 0;
Mat p_kernel;
Mat srcStub;
//Now create a temporary holding matrix
Mat p_tmpMat1, p_tmpMat2, p_tmpMat3, p_tmpMat4;
double noise_power;
nRows = szWindowY;
nCols = szWindowX;
p_kernel = Mat(nRows, nCols, CV_32F, Scalar(1.0 / (double)(nRows * nCols)));
//Local mean of input
filter2D(src, p_tmpMat1, -1, p_kernel, Point(nCols / 2, nRows / 2)); //localMean
//Local variance of input
p_tmpMat2 = src.mul(src);
filter2D(p_tmpMat2, p_tmpMat3, -1, p_kernel, Point(nCols / 2, nRows / 2));
//Subtract off local_mean^2 from local variance
p_tmpMat4 = p_tmpMat1.mul(p_tmpMat1); //localMean^2
p_tmpMat3 = p_tmpMat3 - p_tmpMat4;
// Sub(p_tmpMat3, p_tmpMat4, p_tmpMat3); //filter(in^2) - localMean^2 ==> localVariance
//Estimate noise power
v = mean(p_tmpMat3);
noise_power = v.val[0];
// result = local_mean + ( max(0, localVar - noise) ./ max(localVar, noise)) .* (in - local_mean)
p_tmpMat4 = src - p_tmpMat1; //in - local_mean
p_tmpMat2 = max(p_tmpMat3, noise_power); //max(localVar, noise)
add(p_tmpMat3, Scalar(-noise_power), p_tmpMat3); //localVar - noise
p_tmpMat3 = max(p_tmpMat3, 0); // max(0, localVar - noise)
p_tmpMat3 = (p_tmpMat3 / p_tmpMat2); //max(0, localVar-noise) / max(localVar, noise)
Mat dst = p_tmpMat3.mul(p_tmpMat4);
dst = dst + p_tmpMat1;
_dst.assign(dst);
}
} // namespace mcc
} // namespace cv
@@ -0,0 +1,68 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
/*
* MIT License
*
* Copyright (c) 2018 Pedro Diamel Marrero Fernández
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* @file wiener_filter
* @brief filter wiener for denoise
* @author: Pedro D. Marrero Fernandez
* @data: 17/05/2016
*/
#ifndef _WIENER_FILTER_HPP
#define _WIENER_FILTER_HPP
#include "precomp.hpp"
namespace cv
{
namespace mcc
{
/// CWienerFilter
/** @brief wiener class filter for denoise
* @author: Pedro D. Marrero Fernandez
* @data: 17/05/2016
*/
class CWienerFilter
{
public:
CWienerFilter();
~CWienerFilter();
/** cvWiener2
* @brief A Wiener 2D Filter implementation for OpenCV
* @author: Ray Juang / rayver{ _at_ } hkn{ / _dot_ / } berkeley(_dot_) edu
* @date : 12.1.2006
*/
void wiener2(InputArray _src, OutputArray _dst, int szWindowX, int szWindowY);
};
} // namespace mcc
} // namespace cv
#endif //_WIENER_FILTER_HPP
+46
View File
@@ -0,0 +1,46 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#include <vector>
namespace opencv_test
{
namespace
{
using namespace std;
using namespace cv::mcc;
/****************************************************************************************\
* Test detection works properly on the simplest images
\****************************************************************************************/
void runCCheckerDetectorBasic(std::string image_name, ColorChart chartType)
{
Ptr<CCheckerDetector> detector = CCheckerDetector::create();
std::string path = cvtest::findDataFile("mcc/" + image_name);
cv::Mat img = imread(path);
ASSERT_FALSE(img.empty()) << "Test image can't be loaded: " << path;
detector->setColorChartType(chartType);
ASSERT_TRUE(detector->process(img));
}
TEST(CV_mccRunCCheckerDetectorBasic, accuracy_SG140)
{
runCCheckerDetectorBasic("SG140.png", SG140);
}
TEST(CV_mccRunCCheckerDetectorBasic, accuracy_MCC24)
{
runCCheckerDetectorBasic("MCC24.png", MCC24);
}
TEST(CV_mccRunCCheckerDetectorBasic, accuracy_VINYL18)
{
runCCheckerDetectorBasic("VINYL18.png", VINYL18);
}
} // namespace
} // namespace opencv_test