Merge pull request #1634 from LaurentBerger:FD_bug
* remove bug when src is vector Point2i in FourierDescriptors * remove unused code and commentspull/1646/head
parent
beef60bab5
commit
a798127837
4 changed files with 266 additions and 8 deletions
@ -0,0 +1,169 @@ |
||||
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); |
@ -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.
|
||||
|
||||
#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
|
Loading…
Reference in new issue