1、在一条含有 N 个点的封闭轮廓中,我们可以通过比较每个点与其它点的距离,找出最外层的点。(这个翻译有问题,而且这个问题是实际问题)
a、这样一个算法的复杂度是多少?
b、怎样用更快的速度完成这个任务?
1. We can find the extremal points (i.e., the two points that are farthest apart) in a
closed contour of N points by comparing the distance of each point to every
other point.
a. What is the complexity of such an algorithm?
b. Explain how you can do this faster.
a、O(N*N)
b、Finding the convex hull of the contour,
do the algorithm above at the convex hull .
2、一张 4 x 4 的图像中能包含的最大闭合轮廓有多大? 轮廓面积是多少?
2. What is the maximal closed contour length that could fit into a 4 × 4 image?
What is its contour area?
最大轮廓为12
最带面积 16
3、不使用cv::isContourConvex()函数,描述一个可以用来判断一条闭合轮廓是否为凸轮廓的算法。
3. Describe an algorithm for determining whether a closed contour is convex—
without using cv::isContourConvex().
选择轮廓上的一点,和另一点组成点对
看此点对的连线,是否通过轮廓本身
选择轮廓上的下一点,重复以上过程,直到全部遍历完成。
4.描述能够完成下列任务的算法:
a.判断一个点是否在一条线上。
b.判断一个点是否落在一个三角形内。
c.不使用cv::pointPolygonTest()函数,判断一个点是否在一个多边形内。
4. Describe algorithms:
a. for determining whether a point is above a line.
b. for determining whether a point is inside a triangle.
c. for determining whether a point is inside a polygon—without using
cv::pointPolygonTest().
a、in opencv,we often use two points(eg pa,pb)to describe a line.
SO, when we have a point:" p"
if ( (p.y - pa.y)/(p.x - pa.x) == (pb.y-p.y)/(pb.x - p.x))
the point is above the line
//参考资料 https://www.cnblogs.com/TenosDoIt/p/4024413.html
b.at lease 3 points describe a triangle
(eg pa,pb,pc)
and the target point is "p"
we will build a function GetArea(p1,p2,p3) which will return the area of triangle(p1,p2,p3)
if (
GetArea(pa,pb,c) ==
GetArea(pa,pb,p) +
GetArea(pa,pc,p) +
GetArea(pb,pc,p))
the point is in he triangle(pa,pb,pc)\
c.very like solution b
to a polygon(p1,p2,...,pn)
if(
contourArea(polygon) ==
GetArea(p1,p2,p) +
GetArea(p2,p3,p) +……+
GetArea(pn-1,pn,p)+
GetArea(pn,p1,p))
the point is in he
polygon(p1,p2,...,pn)
5、5.用 PowerPoint 或类似程序,在黑色背景上画出一个半径为 20 的白色的圆(圆的周长是 2 π 20 ≈ 125.7)。 将你画的图保存为图像。
a.读入该图像,将其转化为灰度图,阈值化,然后寻找其中的轮廓。 轮廓长度是多少? 上一题的结果是否与计算得到的长度相同(四舍五入)?
b.将125.7作为轮廓的基长度,分别用基长度的90%、66%、33%、10%作为参数运行cv::approxPolyDP()函数。 寻找轮廓长度,并画出结果。(这句话无法理解?)
5. Using PowerPoint or a similar program, draw a white circle of radius 20 on a
black background (the circle’s circumference will thus be 2 π 20 ≈ 125.7. Save
your drawing as an image.
a. Read the image in, turn it into grayscale, threshold, and find the contour.
What is the contour length? Is it the same (within rounding) or different from
the calculated length?
b. Using 125.7 as a base length of the contour, run cv::approxPolyDP() using as
parameters the following fractions of the base length: 90%, 66%, 33%, 10%.
Find the contour length and draw the results.
a.
int main( int argc, char** argv )
{
//read image,make gray,make bin
Mat src = imread("e:/sandbox/20circle.png",0);
Mat bin;
threshold(src, bin, 0, 255, CV_THRESH_BINARY);
//find contours
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(bin, contours, hierarchy, CV_RETR_TREE, CHAIN_APPROX_NONE, Point(0,0));
//get the arc of the circle
float arc =(float)arcLength(contours[0],true);
printf("contours %.2f\n",arc);
waitKey();
return 0;
}
result is
contours 132.57.
the result is large than the calculated length
b、
int main( int argc, char** argv )
{
//question b
//read image,make gray,make bin
Mat src = imread("e:/sandbox/20circle.png");
Mat gray;
Mat bin;
cvtColor(src,gray,COLOR_BGR2GRAY);
threshold(gray, bin, 0, 255, CV_THRESH_BINARY);
//find contours
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(bin, contours, hierarchy, CV_RETR_TREE, CHAIN_APPROX_NONE, Point(0,0));
//get the arc of the circle
float arc =(float)arcLength(contours[0],true);
printf("contours %.2f\n",arc);
//question c
vector<vector<Point>> contours_poly(contours.size());//用于存放折线点集
Mat draw = src.clone();
for (int i = 0; i<contours.size(); i++)
{
approxPolyDP(Mat(contours[i]), contours_poly[i], 15, true);
drawContours(draw, contours_poly, i, Scalar(0, 255, 255), 2, 8); //绘制
arc =(float)arcLength(contours_poly[0],true);
printf("contours %.2f\n",arc);
}
imshow("approx", draw);
waitKey();
return 0;
}
6、假设我们正在开发一个瓶子检测算子,希望能创造一个“瓶子”特征。 我们有许多瓶子的图像,在这些图像上进行分割和轮廓寻找都很容易,但图中的瓶子都是旋转过的,且大小不一。 我们可以画出轮廓,找到 Hu 矩,以获得一个不变的瓶子特征向量。 至此一切顺利,但我们是否需要画出填充的轮廓,还是只需画出轮廓线即可? 解释你的答案。
6. Suppose we are building a bottle detector and wish to create a “bottle” feature.
We have many images of bottles that are easy to segment and find the contours
of, but the bottles are rotated and come in various sizes. We can draw the con
tours and then find the Hu moments to yield an invariant bottle-feature vector.
So far, so good—but should we draw filled-in contours or just line contours?
Explain your answer.
i think
line contours is enough。
7、
在题6中使用cv::moments()提取瓶子轮廓矩时,我们应该如何设置isBinary标志位? 解释你的答案。
7. When using cv::moments() to extract bottle contour moments in Exercise 6,
how should we set isBinary? Explain your answer.
binaryImage
If it is true, all non-zero image pixels are treated as 1's. The parameter is used for images only.
i think we should keep
binaryImage
=false,and use threshthord to get the bin image.
8、
使用在讨论 Hu 矩时用到的字母形状。 通过对这些形状进行不同角度的旋转和尺度缩放,或二者组合,得到不同的图像。 描述哪些 Hu 特征对应旋转、哪些对应缩放、哪些二者都对应。
8.Take the letter shapes used in the discussion of Hu moments. Produce variant
images of the shapes by rotating to several different angles, scaling larger and
smaller, and combining these transformations. Describe which Hu features
respond to rotation, which to scale, and which to both.
none of the 7 Hu features respond to rotateion,but all to scale.
h1 | h2 | h3 | h4 | h5 | h6 | h7 | |
原图 | -6.92707 | -18.025 | -23.4196 | -30.2727 | -57.5474 | -43.7345 | -57.395 |
顺时针旋转90度 | -6.92707 | -18.025 | -23.4196 | -30.2727 | -57.5474 | -43.7345 | -57.395 |
旋转190度 | -6.92707 | -18.025 | -23.4196 | -30.2727 | -57.5474 | -43.7345 | -57.395 |
放大1倍 | -6.92683 | -18.0452 | -23.4221 | -29.9383 | -56.6541 | -39.3623 | -57.9569 |
放大1倍并旋转180度 | -6.92683 | -18.0452 | -23.4221 | -29.9383 | -56.6541 | -39.3623 | -57.9569 |
//read image,make gray,make bin
Mat src = imread("e:/sandbox/aaa.jpg");
Mat gray;
Mat tmp;
double hu[7];
Moments mts;
cvtColor(src,gray,COLOR_BGR2GRAY);
//original image
tmp = gray.clone();
mts = moments(tmp);
HuMoments(mts, hu);
for (int i=0; i<7; i++)
{
cout << log(abs(hu[i])) <<" ";
}
cout<<endl;
imshow("original image",tmp);
//90_CLOCKWISE
rotate(gray,tmp,cv::ROTATE_90_CLOCKWISE);
mts = moments(tmp);
HuMoments(mts, hu);
for (int i=0; i<7; i++)
{
cout << log(abs(hu[i])) <<" ";
}
cout<<endl;
imshow("90_CLOCKWISE",tmp);
//ROTATE_180
rotate(gray,tmp,cv::ROTATE_180);
mts = moments(tmp);
HuMoments(mts, hu);
for (int i=0; i<7; i++)
{
cout <<log(abs(hu[i])) <<" ";
}
cout<<endl;
imshow("ROTATE_180",tmp);
//pyramid up
pyrUp(gray,tmp);
mts = moments(tmp);
HuMoments(mts, hu);
for (int i=0; i<7; i++)
{
cout <<log(abs(hu[i])) <<" ";
}
cout<<endl;
imshow("pyrup",tmp);
//pyramid up and rotate 180
pyrUp(gray,tmp);
rotate(tmp,tmp,cv::ROTATE_180);
mts = moments(tmp);
HuMoments(mts, hu);
for (int i=0; i<7; i++)
{
cout <<log(abs(hu[i])) <<" ";
}
cout<<endl;
imshow("pyrup and ROTATE_180 ",tmp);
waitKey();
9、
在 Google 图像中搜索“ArUco markers”,选择较大的一些图像。
a.矩适用于寻找 ArUco 图像吗?
b.矩或 Hu 特征适用于读取 ArUco 码吗?
c.cv::matchShapes()函数适用于读取 ArUco 码吗?
9.Go to Google images and search for “ArUco markers.” Choose some larger ones.
a. Are moments good for finding ArUco images?
b. Are moments or Hu features good for reading ArUco codes?
c. Is cv::matchShapes() good for reading ArUco codes?
none of the answer is yes.we have special method to read ArUco markers right.
10、
在 PowerPoint (或其他绘图程序)中创造一个形状,并保存为图像。 将该物体进行缩放、旋转、旋转缩放,并分别储存为图像。 用cv::matchShapes()函数比较它们。
10、Make a shape in PowerPoint (or another drawing program) and save it as an
image. Make a scaled, a rotated, and a rotated and scaled version of the object,
and then store these as images. Compare them using cv::matchShapes().
very like execrise 8,but use another fucntion.
the result is "there are very like"
scaled vs rotated is 1.14219e-005
scaled vs matScaledRotated is 0
matScaledRotated vs rotated is 1.14219e-005
////execrise 10////
// a scaled
Mat matScaled;
pyrUp(gray,matScaled);
// a rotated,
Mat matRotated;
rotate(gray,matRotated,cv::ROTATE_180);
//a rotated and scaled
Mat matScaledRotated;
pyrUp(gray,matScaledRotated);
rotate(matScaledRotated,matScaledRotated,cv::ROTATE_180);
double comres= 0;
comres = matchShapes(matScaled, matRotated,CV_CONTOURS_MATCH_I1, 0.0);
cout<< "scaled vs rotated is "<<comres<<endl;
comres = matchShapes(matScaled, matScaledRotated,CV_CONTOURS_MATCH_I1, 0.0);
cout<< "scaled vs matScaledRotated is "<<comres<<endl;
comres = matchShapes(matScaledRotated, matRotated,CV_CONTOURS_MATCH_I1, 0.0);
cout<< "matScaledRotated vs rotated is "<<comres<<endl;
11.修改形状上下文例子,或修改 OpenCV 3 中的shape_example.cpp例子,用 Hausdorff 距离度量代替形状上下文度量。
11. Modify the shape context example or shape_example.cpp from OpenCV 3 to use
Hausdorff distance instead of a shape context.
very simple,just replace shape context with Hausdorff
the result of the program is
name: ../data/shape_sample/2.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/2.png is: 25.0599
name: ../data/shape_sample/3.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/3.png is: 37.5899
name: ../data/shape_sample/4.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/4.png is: 543.774
name: ../data/shape_sample/5.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/5.png is: 49.93
name: ../data/shape_sample/6.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/6.png is: 75.5844
name: ../data/shape_sample/7.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/7.png is: 115.521
name: ../data/shape_sample/8.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/8.png is: 30.1496
name: ../data/shape_sample/9.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/9.png is: 59.9083
name: ../data/shape_sample/10.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/10.png is: 22.1359
name: ../data/shape_sample/11.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/11.png is: 1.41421
name: ../data/shape_sample/12.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/12.png is: 88.8876
name: ../data/shape_sample/13.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/13.png is: 287.48
name: ../data/shape_sample/14.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/14.png is: 265.017
name: ../data/shape_sample/15.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/15.png is: 74.1687
name: ../data/shape_sample/16.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/16.png is: 35.609
name: ../data/shape_sample/17.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/17.png is: 115.317
name: ../data/shape_sample/18.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/18.png is: 230.078
name: ../data/shape_sample/19.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/19.png is: 14.2127
name: ../data/shape_sample/20.png
distance between ../data/shape_sample/1.png and ../data/shape_sample/20.png is: 210.95
请按任意键继续. . .
the code is
/*
* shape_context.cpp -- Shape context demo for shape matching
*/
#include "stdafx.h"
#include "opencv2/shape.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <opencv2/core/utility.hpp>
#include <iostream>
#include <string>
using namespace std;
using namespace cv;
static void help()
{
printf("\n"
"This program demonstrates a method for shape comparisson based on Shape Context\n"
"You should run the program providing a number between 1 and 20 for selecting an image in the folder ../data/shape_sample.\n"
"Call\n"
"./shape_example [number between 1 and 20, 1 default]\n\n");
}
static vector<Point> simpleContour( const Mat& currentQuery, int n=300 )
{
vector<vector<Point> > _contoursQuery;
vector <Point> contoursQuery;
findContours(currentQuery, _contoursQuery, RETR_LIST, CHAIN_APPROX_NONE);
for (size_t border=0; border<_contoursQuery.size(); border++)
{
for (size_t p=0; p<_contoursQuery[border].size(); p++)
{
contoursQuery.push_back( _contoursQuery[border][p] );
}
}
// In case actual number of points is less than n
int dummy=0;
for (int add=(int)contoursQuery.size()-1; add<n; add++)
{
contoursQuery.push_back(contoursQuery[dummy++]); //adding dummy values
}
// Uniformly sampling
random_shuffle(contoursQuery.begin(), contoursQuery.end());
vector<Point> cont;
for (int i=0; i<n; i++)
{
cont.push_back(contoursQuery[i]);
}
return cont;
}
int main(int argc, char** argv)
{
string path = "../data/shape_sample/";
cv::CommandLineParser parser(argc, argv, "{help h||}{@input|1|}");
if (parser.has("help"))
{
help();
return 0;
}
int indexQuery = parser.get<int>("@input");
if (!parser.check())
{
parser.printErrors();
help();
return 1;
}
if (indexQuery < 1 || indexQuery > 20)
{
help();
return 1;
}
//cv::Ptr <cv::ShapeContextDistanceExtractor> mysc = cv::createShapeContextDistanceExtractor();
cv::Ptr <cv::HausdorffDistanceExtractor> hausdorff_ptr = cv::createHausdorffDistanceExtractor();
Size sz2Sh(300,300);
stringstream queryName;
queryName<<path<<indexQuery<<".png";
Mat query=imread(queryName.str(), IMREAD_GRAYSCALE);
Mat queryToShow;
resize(query, queryToShow, sz2Sh);
imshow("QUERY", queryToShow);
moveWindow("TEST", 0,0);
vector<Point> contQuery = simpleContour(query);
int bestMatch = 0;
float bestDis=FLT_MAX;
for ( int ii=1; ii<=20; ii++ )
{
if (ii==indexQuery) continue;
waitKey(30);
stringstream iiname;
iiname<<path<<ii<<".png";
cout<<"name: "<<iiname.str()<<endl;
Mat iiIm=imread(iiname.str(), 0);
Mat iiToShow;
resize(iiIm, iiToShow, sz2Sh);
imshow("TEST", iiToShow);
moveWindow("TEST", sz2Sh.width+50,0);
vector<Point> contii = simpleContour(iiIm);
float dis = hausdorff_ptr->computeDistance(contQuery, contii );
// float dis = mysc->computeDistance( contQuery, contii );
if ( dis<bestDis )
{
bestMatch = ii;
bestDis = dis;
}
std::cout<<" distance between "<<queryName.str()<<" and "<<iiname.str()<<" is: "<<dis<<std::endl;
}
destroyWindow("TEST");
stringstream bestname;
bestname<<path<<bestMatch<<".png";
Mat iiIm=imread(bestname.str(), 0);
Mat bestToShow;
resize(iiIm, bestToShow, sz2Sh);
imshow("BEST MATCH", bestToShow);
moveWindow("BEST MATCH", sz2Sh.width+50,0);
return 0;
}
12.获得5张含有不同手势的图像。 (在拍照时,穿上黑色外套或者彩色手套,以便选择算法能够找到手的轮廓。)
a.尝试采用cv::matchShapes()辨识手势。
b.尝试采用cv::computeDistance()辨识手势。
c.哪个方法更好?为什么?
12. Get five pictures of five hand gestures. (When taking the photos, either wear a
black coat or a colored glove so that a selection algorithm can find the outline of
the hand.)
a. Try recognizing the gestures with cv::matchShapes().
b. Try recognizing the gestures with cv::computeDistance().
c. Which one works better and why?
这个问题我没有具体回答,但是相关知识可以整理一下
matchshapes使用的是hu矩,这是经典知识,研究的已经很充分了,手势识别这块例子很多,比如
而computdistance基于的是shapeContext,这是一个很厉害的东西,但是现在在opencv里面,包括在其它地方的实现都很有效,这个例子:
还不错。所以,如果识别手势,还是用
matchShapes。毕竟有代码嘛。当然,对shapecontext表示关注。
附件列表
目前方向:图像拼接融合、图像识别 联系方式:jsxyhelu@foxmail.com