Commit a7981278 authored by LaurentBerger's avatar LaurentBerger Committed by Alexander Alekhin

Merge pull request #1634 from LaurentBerger:FD_bug

* remove bug when src is vector Point2i in FourierDescriptors

* remove unused code and comments
parent beef60ba
...@@ -104,11 +104,11 @@ int main(void) ...@@ -104,11 +104,11 @@ int main(void)
vector<Point2f> ctrRef2d, ctrRot2d; vector<Point2f> ctrRef2d, ctrRot2d;
// sampling contour we want 256 points // sampling contour we want 256 points
ximgproc::contourSampling(ctrRef, ctrRef2d, 256); // use a mat ximgproc::contourSampling(ctrRef, ctrRef2d, 256); // use a mat
ximgproc::contourSampling(ctrNoisyRotateShift, ctrRot2d, 256); // use a vector og point ximgproc::contourSampling(ctrNoisyRotateShift, ctrRot2d, 256); // use a vector of points
fit.setFDSize(16); fit.setFDSize(16);
Mat t; Mat t;
fit.estimateTransformation(ctrRot2d, ctrRef2d, t, &dist, false); fit.estimateTransformation(ctrRot2d, ctrRef2d, t, &dist, false);
cout << "Transform *********\n "<<"Origin = "<< t.at<double>(0,0)*ctrNoisy.size() <<" expected "<< (p.origin*ctrNoisy.size()) / 100 <<" ("<< ctrNoisy.size()<<")\n"; cout << "Transform *********\n "<<"Origin = "<< 1-t.at<double>(0,0) <<" expected "<< p.origin/100.0 <<" ("<< ctrNoisy.size()<<")\n";
cout << "Angle = " << t.at<double>(0, 1) * 180 / M_PI << " expected " << p.angle <<"\n"; cout << "Angle = " << t.at<double>(0, 1) * 180 / M_PI << " expected " << p.angle <<"\n";
cout << "Scale = " << t.at<double>(0, 2) << " expected " << p.scale10 / 10.0 << "\n"; cout << "Scale = " << t.at<double>(0, 2) << " expected " << p.scale10 / 10.0 << "\n";
Mat dst; Mat dst;
......
import numpy as np
import cv2 as cv
import math
class ThParameters:
def __init__(self):
self.levelNoise=6
self.angle=45
self.scale10=5
self.origin=10
self.xg=150
self.yg=150
self.update=True
def UpdateShape(x ):
p.update = True
def union(a,b):
x = min(a[0], b[0])
y = min(a[1], b[1])
w = max(a[0]+a[2], b[0]+b[2]) - x
h = max(a[1]+a[3], b[1]+b[3]) - y
return (x, y, w, h)
def intersection(a,b):
x = max(a[0], b[0])
y = max(a[1], b[1])
w = min(a[0]+a[2], b[0]+b[2]) - x
h = min(a[1]+a[3], b[1]+b[3]) - y
if w<0 or h<0: return () # or (0,0,0,0) ?
return (x, y, w, h)
def NoisyPolygon(pRef,n):
# vector<Point> c
p = pRef;
# vector<vector<Point> > contour;
p = p+n*np.random.random_sample((p.shape[0],p.shape[1]))-n/2.0
if (n==0):
return p
c = np.empty(shape=[0, 2])
minX = p[0][0]
maxX = p[0][0]
minY = p[0][1]
maxY = p[0][1]
for i in range( 0,p.shape[0]):
next = i + 1;
if (next == p.shape[0]):
next = 0;
u = p[next] - p[i]
d = int(cv.norm(u))
a = np.arctan2(u[1], u[0])
step = 1
if (n != 0):
step = d // n
for j in range( 1,int(d),int(max(step, 1))):
while True:
pAct = (u*j) / (d)
r = n*np.random.random_sample()
theta = a + 2*math.pi*np.random.random_sample()
# pNew = Point(Point2d(r*cos(theta) + pAct.x + p[i].x, r*sin(theta) + pAct.y + p[i].y));
pNew = np.array([(r*np.cos(theta) + pAct[0] + p[i][0], r*np.sin(theta) + pAct[1] + p[i][1])])
if (pNew[0][0]>=0 and pNew[0][1]>=0):
break
if (pNew[0][0]<minX):
minX = pNew[0][0]
if (pNew[0][0]>maxX):
maxX = pNew[0][0]
if (pNew[0][1]<minY):
minY = pNew[0][1]
if (pNew[0][1]>maxY):
maxY = pNew[0][1]
c = np.append(c,pNew,axis = 0)
return c
#static vector<Point> NoisyPolygon(vector<Point> pRef, double n);
#static void UpdateShape(int , void *r);
#static void AddSlider(String sliderName, String windowName, int minSlider, int maxSlider, int valDefault, int *valSlider, void(*f)(int, void *), void *r);
def AddSlider(sliderName,windowName,minSlider,maxSlider,valDefault, update):
cv.createTrackbar(sliderName, windowName, valDefault,maxSlider-minSlider+1, update)
cv.setTrackbarMin(sliderName, windowName, minSlider)
cv.setTrackbarMax(sliderName, windowName, maxSlider)
cv.setTrackbarPos(sliderName, windowName, valDefault)
# vector<Point> ctrRef;
# vector<Point> ctrRotate, ctrNoisy, ctrNoisyRotate, ctrNoisyRotateShift;
# // build a shape with 5 vertex
ctrRef = np.array([(250,250),(400, 250),(400, 300),(250, 300),(180, 270)])
cg = np.mean(ctrRef,axis=0)
p=ThParameters()
cv.namedWindow("FD Curve matching");
# A rotation with center at (150,150) of angle 45 degrees and a scaling of 5/10
AddSlider("Noise", "FD Curve matching", 0, 20, p.levelNoise, UpdateShape)
AddSlider("Angle", "FD Curve matching", 0, 359, p.angle, UpdateShape)
AddSlider("Scale", "FD Curve matching", 5, 100, p.scale10, UpdateShape)
AddSlider("Origin", "FD Curve matching", 0, 100, p.origin, UpdateShape)
AddSlider("Xg", "FD Curve matching", 150, 450, p.xg, UpdateShape)
AddSlider("Yg", "FD Curve matching", 150, 450, p.yg, UpdateShape)
code = 0
img = np.zeros((300,512,3), np.uint8)
print ("******************** PRESS g TO MATCH CURVES *************\n")
while (code!=27):
code = cv.waitKey(60)
if p.update:
p.levelNoise=cv.getTrackbarPos('Noise','FD Curve matching')
p.angle=cv.getTrackbarPos('Angle','FD Curve matching')
p.scale10=cv.getTrackbarPos('Scale','FD Curve matching')
p.origin=cv.getTrackbarPos('Origin','FD Curve matching')
p.xg=cv.getTrackbarPos('Xg','FD Curve matching')
p.yg=cv.getTrackbarPos('Yg','FD Curve matching')
r = cv.getRotationMatrix2D((p.xg, p.yg), angle=p.angle, scale=10.0/ p.scale10);
ctrNoisy= NoisyPolygon(ctrRef,p.levelNoise)
ctrNoisy1 = np.reshape(ctrNoisy,(ctrNoisy.shape[0],1,2))
ctrNoisyRotate = cv.transform(ctrNoisy1,r)
ctrNoisyRotateShift = np.empty([ctrNoisyRotate.shape[0],1,2],dtype=np.int32)
for i in range(0,ctrNoisy.shape[0]):
k=(i+(p.origin*ctrNoisy.shape[0])//100)% ctrNoisyRotate.shape[0]
ctrNoisyRotateShift[i] = ctrNoisyRotate[k]
# To draw contour using drawcontours
cc= np.reshape(ctrNoisyRotateShift,[ctrNoisyRotateShift.shape[0],2])
c = [ ctrRef,cc]
p.update = False;
rglobal =(0,0,0,0)
for i in range(0,2):
r = cv.boundingRect(c[i])
rglobal = union(rglobal,r)
r = list(rglobal)
r[2] = r[2]+10
r[3] = r[3]+10
rglobal = tuple(r)
img = np.zeros((2 * rglobal[3], 2 * rglobal[2], 3), np.uint8)
cv.drawContours(img, c, 0, (255,0,0),1);
cv.drawContours(img, c, 1, (0, 255, 0),1);
cv.circle(img, tuple(c[0][0]), 5, (255, 0, 0),3);
cv.circle(img, tuple(c[1][0]), 5, (0, 255, 0),3);
cv.imshow("FD Curve matching", img);
if code == ord('d') :
cv.destroyWindow("FD Curve matching");
cv.namedWindow("FD Curve matching");
# A rotation with center at (150,150) of angle 45 degrees and a scaling of 5/10
AddSlider("Noise", "FD Curve matching", 0, 20, p.levelNoise, UpdateShape)
AddSlider("Angle", "FD Curve matching", 0, 359, p.angle, UpdateShape)
AddSlider("Scale", "FD Curve matching", 5, 100, p.scale10, UpdateShape)
AddSlider("Origin%%", "FD Curve matching", 0, 100, p.origin, UpdateShape)
AddSlider("Xg", "FD Curve matching", 150, 450, p.xg, UpdateShape)
AddSlider("Yg", "FD Curve matching", 150, 450, p.yg, UpdateShape)
if code == ord('g'):
fit = cv.ximgproc.createContourFitting(1024,16);
# sampling contour we want 256 points
cn= np.reshape(ctrRef,[ctrRef.shape[0],1,2])
ctrRef2d = cv.ximgproc.contourSampling(cn, 256)
ctrRot2d = cv.ximgproc.contourSampling(ctrNoisyRotateShift, 256)
fit.setFDSize(16)
c1 = ctrRef2d
c2 = ctrRot2d
alphaPhiST, dist = fit.estimateTransformation(ctrRot2d, ctrRef2d)
print( "Transform *********\n Origin = ", 1-alphaPhiST[0,0] ," expected ", p.origin / 100. ,"\n")
print( "Angle = ", alphaPhiST[0,1] * 180 / math.pi ," expected " , p.angle,"\n")
print( "Scale = " ,alphaPhiST[0,2] ," expected " , p.scale10 / 10.0 , "\n")
dst = cv.ximgproc.transformFD(ctrRot2d, alphaPhiST,cn, False);
ctmp= np.reshape(dst,[dst.shape[0],2])
cdst=ctmp.astype(int)
c = [ ctrRef,cc,cdst]
cv.drawContours(img, c, 2, (0,0,255),1);
cv.circle(img, (int(c[2][0][0]),int(c[2][0][1])), 5, (0, 0, 255),5);
cv.imshow("FD Curve matching", img);
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#include "precomp.hpp" #include "precomp.hpp"
#include <math.h> #include <math.h>
#include <vector> #include <vector>
#include <iostream>
/* /*
If you use this code please cite this @cite BergerRaghunathan1998 If you use this code please cite this @cite BergerRaghunathan1998
...@@ -107,7 +106,7 @@ void ContourFitting::estimateTransformation(InputArray _src, InputArray _ref, Ou ...@@ -107,7 +106,7 @@ void ContourFitting::estimateTransformation(InputArray _src, InputArray _ref, Ou
void ContourFitting::estimateTransformation(InputArray _src, InputArray _ref, OutputArray _alphaPhiST,double *distFin, bool fdContour) void ContourFitting::estimateTransformation(InputArray _src, InputArray _ref, OutputArray _alphaPhiST,double *distFin, bool fdContour)
{ {
if (!fdContour) if (!fdContour)
CV_Assert( _src.kind() == _InputArray::STD_VECTOR && _ref.kind() == _InputArray::STD_VECTOR); CV_Assert( (_src.kind() == _InputArray::STD_VECTOR || _src.kind() == _InputArray::MAT) && (_ref.kind() == _InputArray::STD_VECTOR || _ref.kind() == _InputArray::MAT));
else else
CV_Assert(fdContour && _src.kind() == _InputArray::MAT && _ref.kind() == _InputArray::MAT); CV_Assert(fdContour && _src.kind() == _InputArray::MAT && _ref.kind() == _InputArray::MAT);
CV_Assert(_src.channels() == 2 && _ref.channels() == 2); CV_Assert(_src.channels() == 2 && _ref.channels() == 2);
...@@ -220,6 +219,8 @@ void fourierDescriptor(InputArray _src, OutputArray _dst, int nbElt, int nbFD) ...@@ -220,6 +219,8 @@ void fourierDescriptor(InputArray _src, OutputArray _dst, int nbElt, int nbFD)
Mat Z; Mat Z;
if (z.rows*z.cols!=nbElt) if (z.rows*z.cols!=nbElt)
contourSampling(_src, z,nbElt); contourSampling(_src, z,nbElt);
else if (_src.depth() == CV_32S)
z.convertTo(z, CV_32F);
dft(z, Z, DFT_SCALE | DFT_REAL_OUTPUT); dft(z, Z, DFT_SCALE | DFT_REAL_OUTPUT);
if (nbFD == -1) if (nbFD == -1)
{ {
...@@ -250,13 +251,12 @@ void contourSampling(InputArray _src, OutputArray _out, int nbElt) ...@@ -250,13 +251,12 @@ void contourSampling(InputArray _src, OutputArray _out, int nbElt)
} }
CV_Assert(ctr.rows==1 || ctr.cols==1); CV_Assert(ctr.rows==1 || ctr.cols==1);
double l1 = 0, l2, p, d, s; double l1 = 0, l2, p, d, s;
// AutoBuffer<Point2d> _buf(nbElt);
Mat r; Mat r;
if (ctr.rows==1) if (ctr.rows==1)
ctr=ctr.t(); ctr=ctr.t();
int j = 0; int j = 0;
int nb = ctr.rows; int nb = ctr.rows;
p = arcLength(_src, true); p = arcLength(ctr, true);
l2 = norm(ctr.row(j) - ctr.row(j + 1)) / p; l2 = norm(ctr.row(j) - ctr.row(j + 1)) / p;
for (int i = 0; i<nbElt; i++) for (int i = 0; i<nbElt; i++)
{ {
...@@ -275,7 +275,6 @@ void contourSampling(InputArray _src, OutputArray _out, int nbElt) ...@@ -275,7 +275,6 @@ void contourSampling(InputArray _src, OutputArray _out, int nbElt)
Mat d10 = d1 - d0; Mat d10 = d1 - d0;
Mat pn = d0 + d10 * (s - l1) / (l2 - l1); Mat pn = d0 + d10 * (s - l1) / (l2 - l1);
r.push_back(pn); r.push_back(pn);
// _buf[i]=Point2d(pn.at<Point2f>(0,0));
} }
} }
r.copyTo(_out); r.copyTo(_out);
...@@ -284,7 +283,7 @@ void contourSampling(InputArray _src, OutputArray _out, int nbElt) ...@@ -284,7 +283,7 @@ void contourSampling(InputArray _src, OutputArray _out, int nbElt)
void transformFD(InputArray _src, InputArray _t,OutputArray _dst, bool fdContour) void transformFD(InputArray _src, InputArray _t,OutputArray _dst, bool fdContour)
{ {
if (!fdContour) if (!fdContour)
CV_Assert(_src.kind() == _InputArray::STD_VECTOR); CV_Assert(_src.kind() == _InputArray::STD_VECTOR || _src.kind() == _InputArray::MAT);
else else
CV_Assert( _src.kind() == _InputArray::MAT ); CV_Assert( _src.kind() == _InputArray::MAT );
CV_Assert(_src.channels() == 2); CV_Assert(_src.channels() == 2);
......
// 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"
namespace opencv_test { namespace {
TEST(ximpgroc_fourierdescriptors,test_FD_AND_FIT)
{
Mat fd;
vector<Point2f> ctr(16);
float Rx = 100, Ry = 100;
Point2f g(0, 0);
float angleOri = 0;
for (int i = 0; i < static_cast<int>(ctr.size()); i++)
{
float theta = static_cast<float>(2 * CV_PI / static_cast<int>(ctr.size()) * i + angleOri);
ctr[i] = Point2f(Rx * cos(theta) + g.x, Ry * sin(theta) + g.y);
}
ximgproc::fourierDescriptor(ctr, fd);
CV_Assert(cv::norm(fd.at<Vec2f>(0, 0)) < ctr.size() * FLT_EPSILON && cv::norm(fd.at<Vec2f>(0, 1) - Vec2f(Rx, 0)) < ctr.size() * FLT_EPSILON);
Rx = 100, Ry = 50;
g = Point2f(50, 20);
for (int i = 0; i < static_cast<int>(ctr.size()); i++)
{
float theta = static_cast<float>(2 * CV_PI / static_cast<int>(ctr.size()) * i + angleOri);
ctr[i] = Point2f(Rx * cos(theta) + g.x, Ry * sin(theta) + g.y);
}
ximgproc::fourierDescriptor(ctr, fd);
CV_Assert(cv::norm(fd.at<Vec2f>(0, 0) - Vec2f(g)) < 1 &&
fabs(fd.at<Vec2f>(0, 1)[0] + fd.at<Vec2f>(0, static_cast<int>(ctr.size()) - 1)[0] - Rx) < 1 &&
fabs(fd.at<Vec2f>(0, 1)[0] - fd.at<Vec2f>(0, static_cast<int>(ctr.size()) - 1)[0] - Ry) < 1);
Rx = 70, Ry = 100;
g = Point2f(30, 100);
angleOri = static_cast<float>(CV_PI / 4);
for (int i = 0; i < static_cast<int>(ctr.size()); i++)
{
float theta = static_cast<float>(2 * CV_PI / static_cast<int>(ctr.size()) * i + CV_PI / 4);
ctr[i] = Point2f(Rx * cos(theta) + g.x, Ry * sin(theta) + g.y);
}
ximgproc::fourierDescriptor(ctr, fd);
CV_Assert(cv::norm(fd.at<Vec2f>(0, 0) - Vec2f(g)) < 1);
CV_Assert(cv::norm(Vec2f((Rx + Ry)*cos(angleOri) / 2, (Rx + Ry)*sin(angleOri) / 2) - fd.at<Vec2f>(0, 1)) < 1);
CV_Assert(cv::norm(Vec2f((Rx - Ry)*cos(angleOri) / 2, -(Rx - Ry)*sin(angleOri) / 2) - fd.at<Vec2f>(0, static_cast<int>(ctr.size()) - 1)) < 1);
RNG rAlea;
g.x = 0; g.y = 0;
ctr.resize(256);
for (int i = 0; i < static_cast<int>(ctr.size()); i++)
{
ctr[i] = Point2f(rAlea.uniform(0.0F, 1.0F), rAlea.uniform(0.0F, 1.0F));
g += ctr[i];
}
g.x = g.x / ctr.size();
g.y = g.y / ctr.size();
double rotAngle = 35;
double s = 0.1515;
Mat r = getRotationMatrix2D(g, rotAngle, 0.1515);
vector<Point2f> unknownCtr;
vector<Point2f> ctrShift;
int valShift = 170;
for (int i = 0; i < static_cast<int>(ctr.size()); i++)
ctrShift.push_back(ctr[(i + valShift) % ctr.size()]);
cv::transform(ctrShift, unknownCtr, r);
ximgproc::ContourFitting fit;
fit.setFDSize(16);
Mat t;
double dist;
fit.estimateTransformation(unknownCtr, ctr, t, &dist, false);
CV_Assert(fabs(t.at<double>(0, 0)*ctr.size() + valShift) < 10 || fabs((1 - t.at<double>(0, 0))*ctr.size() - valShift) < 10);
CV_Assert(fabs(t.at<double>(0, 1) - rotAngle / 180.*CV_PI) < 0.1);
CV_Assert(fabs(t.at<double>(0, 2) - 1 / s) < 0.1);
ctr.resize(4);
ctr[0] = Point2f(0, 0);
ctr[1] = Point2f(16, 0);
ctr[2] = Point2f(16, 16);
ctr[3] = Point2f(0, 16);
double squareArea = contourArea(ctr), lengthSquare = arcLength(ctr, true);
Mat ctrs;
ximgproc::contourSampling(ctr, ctrs, 64);
CV_Assert(fabs(squareArea - contourArea(ctrs)) < FLT_EPSILON);
CV_Assert(fabs(lengthSquare - arcLength(ctrs, true)) < FLT_EPSILON);
}
}} // namespace
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment