Skip to content

Added some helper function in 'mcc' #2644

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: 4.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions modules/mcc/include/opencv2/mcc/checker_model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,29 @@ class CV_EXPORTS_W CChecker

CV_WRAP virtual void setTarget(TYPECHART _target) = 0;
CV_WRAP virtual void setBox(std::vector<Point2f> _box) = 0;
CV_WRAP virtual void setPerPatchCosts(std::vector<Point2f> _patchCosts) = 0;

// Detected directly by the detector or found using geometry, useful to determine if a patch is occluded
CV_WRAP virtual void setBoxDetectionType(std::vector<std::vector<Point2f>> detectionType) = 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 void setPatchCenters(std::vector<Point2f> _patchCenters) = 0;
CV_WRAP virtual void setPatchBoundingBoxes(std::vector<Point2f> _patchBoundingBoxes) = 0;

CV_WRAP virtual TYPECHART getTarget() = 0;
CV_WRAP virtual std::vector<Point2f> getBox() = 0;
CV_WRAP virtual std::vector<Point2f> getPerPatchCosts() = 0;
CV_WRAP virtual std::vector<std::vector<Point2f>> getBoxDetectionType() = 0;
CV_WRAP virtual Mat getChartsRGB() = 0;
CV_WRAP virtual Mat getChartsYCbCr() = 0;
CV_WRAP virtual float getCost() = 0;
CV_WRAP virtual Point2f getCenter() = 0;
CV_WRAP virtual std::vector<Point2f> getPatchCenters() = 0;
CV_WRAP virtual std::vector<Point2f> getPatchBoundingBoxes(float sideRatio=0.5) =0;

CV_WRAP virtual bool calculate() = 0; ///< Return false if some error occured, true otherwise
};

/** \brief checker draw
Expand All @@ -115,10 +127,16 @@ class CV_EXPORTS_W CCheckerDraw
public:
virtual ~CCheckerDraw() {}
/** \brief Draws the checker to the given image.
* \param img image in color space BGR
* \param img image in color space BGR, original image gets modified
* \param sideRatio ratio between the side length of drawed boxes, and the actual side of squares
* keeping sideRatio = 1.0 is not recommended as the border can be a bit inaccurate
* in detection, for best output keep it at less than 1.0
* \param drawActualDetection draw the actually detected patch,i.e,, the non occuled ones,
* useful for debugging, default (false)
* \return void
*/
CV_WRAP virtual void draw(InputOutputArray img) = 0;
CV_WRAP virtual void draw(InputOutputArray img, float sideRatio = 0.5,
bool drawActualDetection = false) = 0;
/** \brief Create a new CCheckerDraw object.
* \param pChecker The checker which will be drawn by this object.
* \param color The color by with which the squares of the checker
Expand All @@ -132,6 +150,20 @@ class CV_EXPORTS_W CCheckerDraw
int thickness = 2);
};


/** @brief draws a single mcc::ColorChecker on the given image
* This is a functional version of the CCheckerDraw class, provided for convenience
* \param img image in color space BGR, it gets changed by this call
* \param pChecker pointer to the CChecker, which contains the detection
* \param color color used for drawing
* \param thickness thickness of the boxes drawed
* \param sideRatio ratio between the side length of drawed boxes, and the actual side of squares
* keeping sideRatio = 1.0 is not recommended as the border can be a bit inaccurate
* in detection, for best output keep it at less than 1.0
*/
CV_EXPORTS_W void drawColorChecker(InputOutputArray img, Ptr<CChecker> pChecker,
cv::Scalar color = CV_RGB(0, 255, 0), int thickness = 2, float sideRatio = 0.5,
bool drawActualDetection = false);
//! @} mcc
} // namespace mcc
} // namespace cv
Expand Down
1 change: 1 addition & 0 deletions modules/mcc/samples/chart_detection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ int main(int argc, char *argv[])
if (!parser.check())
{
parser.printErrors();
parser.printMessage();
return 0;
}

Expand Down
1 change: 1 addition & 0 deletions modules/mcc/samples/chart_detection_with_network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ int main(int argc, char *argv[])
if (!parser.check())
{
parser.printErrors();
parser.printMessage();
return 0;
}

Expand Down
80 changes: 40 additions & 40 deletions modules/mcc/src/checker_detector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,8 @@ bool CCheckerDetectorImpl::
//-------------------------------------------------------------------

std::vector<std::vector<cv::Point2f>> colorCharts;
checkerRecognize(img_bgr, detectedCharts, G, chartType, colorCharts, params);
std::vector<std::vector<CChart>> groupedCharts;
checkerRecognize(img_bgr, detectedCharts, G, chartType, colorCharts,groupedCharts, params);

if (colorCharts.empty())
continue;
Expand All @@ -219,7 +220,7 @@ bool CCheckerDetectorImpl::
// checker color analysis
//-------------------------------------------------------------------
std::vector<Ptr<CChecker>> checkers;
checkerAnalysis(img_rgb_f, chartType, nc, colorCharts, checkers, asp, params,
checkerAnalysis(img_rgb_f, chartType, nc, colorCharts, groupedCharts, checkers, asp, params,
img_rgb_org, img_ycbcr_org, rgb_planes, ycbcr_planes);

#ifdef MCC_DEBUG
Expand All @@ -237,6 +238,10 @@ bool CCheckerDetectorImpl::
for (cv::Point2f &corner : checker->getBox())
corner += static_cast<cv::Point2f>(region.tl());

for (std::vector<cv::Point2f> &corners : checker->getBoxDetectionType())
for (cv::Point2f & corner: corners)
corner += static_cast<cv::Point2f>(region.tl());

mtx.lock(); // push_back is not thread safe
m_checkers.push_back(checker);
mtx.unlock();
Expand Down Expand Up @@ -414,7 +419,8 @@ bool CCheckerDetectorImpl::
//-------------------------------------------------------------------

std::vector<std::vector<cv::Point2f>> colorCharts;
checkerRecognize(img_bgr, detectedCharts, G, chartType, colorCharts, params);
std::vector<std::vector<CChart>> groupedCharts;
checkerRecognize(img_bgr, detectedCharts, G, chartType, colorCharts, groupedCharts, params);

if (colorCharts.empty())
continue;
Expand All @@ -440,7 +446,7 @@ bool CCheckerDetectorImpl::
// checker color analysis
//-------------------------------------------------------------------
std::vector<Ptr<CChecker>> checkers;
checkerAnalysis(img_rgb_f, chartType, nc, colorCharts, checkers, asp, params,
checkerAnalysis(img_rgb_f, chartType, nc, colorCharts,groupedCharts, checkers, asp, params,
img_rgb_org, img_ycbcr_org, rgb_planes, ycbcr_planes);
#ifdef MCC_DEBUG
cv::Mat image_checker;
Expand All @@ -456,6 +462,10 @@ bool CCheckerDetectorImpl::
{
for (cv::Point2f &corner : checker->getBox())
corner += static_cast<cv::Point2f>(region.tl() + innerRegion.tl());
for (std::vector<cv::Point2f> &corners : checker->getBoxDetectionType())
for (cv::Point2f & corner: corners)
corner += static_cast<cv::Point2f>(region.tl() + innerRegion.tl());
checker->calculate();
mtx.lock(); // push_back is not thread safe
m_checkers.push_back(checker);
mtx.unlock();
Expand Down Expand Up @@ -756,6 +766,7 @@ void CCheckerDetectorImpl::
const std::vector<int> &G,
const TYPECHART chartType,
std::vector<std::vector<cv::Point2f>> &colorChartsOut,
std::vector<std::vector<CChart>> &groupedCharts,
const Ptr<DetectorParameters> &params)
{
std::vector<int> gU;
Expand All @@ -775,7 +786,7 @@ void CCheckerDetectorImpl::
for (size_t i = 0; i < Ncc; i++)
if (G[i] == (int)g)
chartSub.push_back(detectedCharts[i]);

std::vector<CChart> chartSubCopy = chartSub;
size_t Nsc = chartSub.size();
if (Nsc < params->minGroupSize)
continue;
Expand Down Expand Up @@ -958,6 +969,7 @@ void CCheckerDetectorImpl::
mcc::polyclockwise(ibox);
// circshift(ibox, 4 - iTheta);
colorCharts.push_back(ibox);
groupedCharts.push_back(chartSubCopy);
}

// return
Expand All @@ -970,6 +982,7 @@ void CCheckerDetectorImpl::
const TYPECHART chartType,
const unsigned int nc,
const std::vector<std::vector<cv::Point2f>> &colorCharts,
const std::vector<std::vector<CChart>> &groupedCharts,
std::vector<Ptr<CChecker>> &checkers,
float asp,
const Ptr<DetectorParameters> &params,
Expand All @@ -993,10 +1006,11 @@ void CCheckerDetectorImpl::

N = colorCharts.size();
std::vector<float> J(N);
std::vector<Point2f> perPatchCost(N);
for (size_t i = 0; i < N; i++)
{
ibox = colorCharts[i];
J[i] = cost_function(img_f, mask, lab, ibox, chartType);
J[i] = cost_function(img_f, mask, lab, perPatchCost, ibox, chartType);
}

std::vector<int> idx;
Expand All @@ -1020,14 +1034,28 @@ void CCheckerDetectorImpl::
get_profile(ibox, chartType, charts_rgb, charts_ycbcr, img_rgb_org,
img_ycbcr_org, rgb_planes, ycbcr_planes);

std::vector<std::vector<Point2f>> directlyDetectedPatches;
for(auto chart : groupedCharts[idx[i]])
{
for(auto &corners: chart.corners)
corners *= invAsp;
directlyDetectedPatches.push_back(chart.corners);
}



// result
Ptr<CChecker> checker = CChecker::create();
checker->setBox(ibox);
checker->setBoxDetectionType(directlyDetectedPatches);

checker->setTarget(chartType);
checker->setChartsRGB(charts_rgb);
checker->setChartsYCbCr(charts_ycbcr);
checker->setCenter(mace_center(ibox));
checker->setCost(J[i]);
checker->calculate(); //does some precomputation based on the inputs,
//mainly used to keep the code a bit clean

checkers.push_back(checker);
}
Expand Down Expand Up @@ -1178,38 +1206,6 @@ void CCheckerDetectorImpl::
x_new.insert(x_new.begin() + idx + 1, (x_new[idx] + x_new[idx + 1]) / 2);
}

void CCheckerDetectorImpl::
transform_points_forward(InputArray T, const std::vector<cv::Point2f> &X, std::vector<cv::Point2f> &Xt)
{
size_t N = X.size();
if (N == 0)
return;

Xt.clear();
Xt.resize(N);
cv::Matx31f p, xt;
cv::Point2f pt;

cv::Matx33f _T = T.getMat();
for (int i = 0; i < (int)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;
}
}

void CCheckerDetectorImpl::
transform_points_inverse(InputArray T, const std::vector<cv::Point2f> &X, std::vector<cv::Point2f> &Xt)
{
cv::Matx33f _T = T.getMat();
cv::Matx33f Tinv = _T.inv();
transform_points_forward(Tinv, X, Xt);
}
void CCheckerDetectorImpl::
get_profile(
const std::vector<cv::Point2f> &ibox,
Expand Down Expand Up @@ -1330,6 +1326,7 @@ void CCheckerDetectorImpl::

float CCheckerDetectorImpl::
cost_function(InputArray im_rgb, InputOutputArray mask, InputArray lab,
std::vector<Point2f> &perPatchCost,
const std::vector<cv::Point2f> &ibox, const TYPECHART chartType)
{
CChartModel cccm(chartType);
Expand All @@ -1342,6 +1339,8 @@ float CCheckerDetectorImpl::

int N = (int)(cellchart.size() / 4);

perPatchCost.assign(N, {-1, -1}); //-1 for patches outside the image

cv::Mat _lab = lab.getMat();
cv::Mat _im_rgb = im_rgb.getMat();

Expand Down Expand Up @@ -1376,10 +1375,11 @@ float CCheckerDetectorImpl::
// cos error
float costh;
costh = (float)(mu.dot(cv::Scalar(r)) / (norm(mu) * norm(r) + FLT_EPSILON));
ec += (1 - (1 + costh) / 2);
perPatchCost[i] = {1 - (1 + costh)/2, (float)st.dot(st)};
ec += perPatchCost[i].x;

// standar desviation
es += (float)st.dot(st);
es += perPatchCost[i].y;
}
}

Expand Down
18 changes: 6 additions & 12 deletions modules/mcc/src/checker_detector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,10 @@ class CCheckerDetectorImpl : public CCheckerDetector
* \param[out] colorChartsOut
*/
virtual void
checkerRecognize(InputArray img, const std::vector<CChart> &detectedCharts, const std::vector<int> &G,
const TYPECHART chartType, std::vector<std::vector<cv::Point2f>> &colorChartsOut,
checkerRecognize(InputArray img, const std::vector<CChart> &detectedCharts,
const std::vector<int> &G, const TYPECHART chartType,
std::vector<std::vector<cv::Point2f>> &colorChartsOut,
std::vector<std::vector<CChart>> &groupedCharts,
const Ptr<DetectorParameters> &params);

/// checkerAnalysis
Expand All @@ -146,6 +148,7 @@ class CCheckerDetectorImpl : public CCheckerDetector
checkerAnalysis(InputArray img_rgb_f,
const TYPECHART chartType, const unsigned int nc,
const std::vector<std::vector<cv::Point2f>> &colorCharts,
const std::vector<std::vector<CChart>> &groupedCharts,
std::vector<Ptr<CChecker>> &checkers, float asp,
const Ptr<DetectorParameters> &params,
const cv::Mat &img_rgb_org,
Expand All @@ -172,16 +175,6 @@ class CCheckerDetectorImpl : public CCheckerDetector
std::vector<float> &x_new,
float tol);

void transform_points_forward(
InputArray T,
const std::vector<cv::Point2f> &X,
std::vector<cv::Point2f> &Xt);

void transform_points_inverse(
InputArray T,
const std::vector<cv::Point2f> &X,
std::vector<cv::Point2f> &Xt);

void get_profile(
const std::vector<cv::Point2f> &ibox,
const TYPECHART chartType,
Expand All @@ -197,6 +190,7 @@ class CCheckerDetectorImpl : public CCheckerDetector
* + \sum_k || \sigma_{k,p} ||^2
*/
float cost_function(InputArray img, InputOutputArray mask, InputArray lab,
std::vector<cv::Point2f> &perPatchCost,
const std::vector<cv::Point2f> &ibox,
const TYPECHART chartType);
};
Expand Down
Loading