Unable to generate Freeman chain code using OpenCv
I have some 77 vertices data.I am trying to generate freeman chain code for this contour using OpenCv in C++.
I have written the following function.This function basically takes the x and y values as inputs and generates a freeman chain code.
void GenerateFreemanChainCode(std::vector<double> X, std::vector<double> Y, std::vector<char> &freemanChainCode)
{
cv::Mat img = cv::Mat::zeros(2, 2, CV_8UC1);
for (int Idx = 0; Idx < X.size()-1; Idx++)
{
cv::line(img, Point(X.at(Idx), Y.at(Idx)), Point(X.at(Idx+1), Y.at(Idx+1)), cv::Scalar(255), 1);
}
imshow("Test", img);
vector<vector<Point> > contours;
findContours(img, contours, RETR_EXTERNAL, CV_CHAIN_CODE);
//cout << Mat(contours[0]) << endl;
findContours(img, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
//cout << "CHAIN_APPROX_SIMPLE" << endl;
//cout << Mat(contours[0]) << endl;
CvChain* chain = 0;
CvMemStorage* storage = 0;
storage = cvCreateMemStorage(0);
cvFindContours(&IplImage(img), storage, (CvSeq**)(&chain), sizeof(*chain), CV_RETR_EXTERNAL, CV_CHAIN_CODE);
for (; chain != NULL; chain = (CvChain*)chain->h_next)
{
//chain=(CvChain*)chain ->h_next;
//if(chain==NULL){break;}
CvSeqReader reader;
int i, total = chain->total;
cvStartReadSeq((CvSeq*)chain, &reader, 0);
//printf("--------------------chain\n");
for (i = 0; i<total; i++)
{
char code;
CV_READ_SEQ_ELEM(code, reader);
//printf("%d", code);
freemanChainCode.push_back(code);
}
}
}
My vertices data looks as follows(X,Y Data seperate by space):
0 0
0 0.00144928
0.00144928 0.00144928
0.00289855 0.00144928
0.00724638 0.00434783
0.015942 0.00434783
0.0275362 0.00434783
0.0434783 0.00434783
0.0637681 0.00434783
0.0782609 0.00434783
0.0869565 0.00434783
0.102899 0.0057971
0.111594 0.0057971
0.126087 0.0057971
0.136232 0.0057971
0.15942 0.0057971
0.172464 0.0057971
0.182609 0.00434783
0.198551 0.00434783
0.214493 0.00434783
0.23913 0.00434783
0.250725 0.00434783
0.269565 0.00434783
0.284058 0.00434783
0.305797 0.00434783
0.331884 0.00434783
0.344928 0.00434783
0.371014 0.0057971
0.386957 0.0057971
0.402899 0.00724638
0.423188 0.00724638
0.436232 0.00724638
0.45942 0.00724638
0.47971 0.00724638
0.5 0.00724638
0.513043 0.00724638
0.524638 0.00724638
0.553623 0.00724638
0.578261 0.00724638
0.592754 0.00724638
0.602899 0.00724638
0.62029 0.00724638
0.634783 0.00724638
0.646377 0.00724638
0.672464 0.00724638
0.686957 0.00724638
0.701449 0.00724638
0.718841 0.00724638
0.737681 0.00724638
0.763768 0.00724638
0.773913 0.00724638
0.797101 0.00724638
0.817391 0.00724638
0.824638 0.00724638
0.826087 0.00724638
0.831884 0.00724638
0.846377 0.00724638
0.862319 0.00724638
0.886957 0.00724638
0.895652 0.00724638
0.902899 0.00724638
0.917391 0.00724638
0.928986 0.00724638
0.949275 0.00724638
0.965217 0.00724638
0.997101 0.00869565
1 0.00869565
I would be really glad,if someone can help me ,ideintify the mistake. Thanks in advance.
which opencv version are you using here ?
also: cv::line() expects integer coords, not double. where do you get those contours from, originally ?
I am using 3.4.3. I have a software,which records the vertices data,while user creates a certain geometrical figure.So,I get the vertices data from that.What do you suggest here then?
i can only guess, but your lines probably end up in a single point at (1,0).
you could try to scale the vertices with the image size.
then, using deprecated 1.0 c-api code is mostly a bad idea. not sure even, if findContours() still calculates a freeman chain. (maybe you're better off, doing that manually)
Basically, from my vertices raw data, I am scaling the data,such that both x and y coordinate values lie between 0 and 1. Could you please elaborate a bit more, as to ,how I can modify my code to scale my vertices data with image size. In the above code, I guess, the image size is 2/2 right? Could you please explain the changes to be done exactly.
well, that's problem #1. make it : x=[0..w] y=[0..h] instead.
also, the image you draw to, should be significantly larger, like 256x256.
do you understand, that pixel coords are integers ?
ah I see! So, since currently I have my x and y values between 0 and 1,I would multiply each x value with W and y value with H and then case each value to integer.I will also make the following change in the code. cv::Mat img = cv::Mat::zeros(256, 256, CV_8UC1);
That should be enough right?
that would at least solve the 1st half of your program.
i'm not sure, if findContours() still calculates freeman chains correctly, and the c-api code you're trying with is definitely no more maintained.
it might be better / easier, to calculate the chains from scratch
Yes,I quickly tested with some of my sample data,which I have.The code is is able to generate the chain code,for each data set (I mean,for each vertices data,now I have one freeman chain code).I now,want your suggestion regarding my approach. I basically have training data in case of some geometrical figures such as Line,Circle, Ellipse,Square and Arc. For any given data set,I want to classify my geometrical figure as one of these 5 types. So, once I generate the freeman chain code my trainingset as well as testing dataset. As we know, freeman chain code consists of values,from 0-7,I am calculating the count of 0's,1's...and 7's for testing and training dataset and finally,just calculating the distance as {|xo-so| +..|x7-s7|},where x0 is no. of zeros in dataset1,s0 is no. of ...(more)
yea, now it gets interesting ;)
what you're doing is basically a "histogram" comparison, right ?
since your contours / chains will differ in length, you probably have to normalize the histograms before the comparison, also there is
compareHist()
which offers some other distance metrics apart from L2 (e.g. chi-sqr)my objection to this would be, that it is loosing the order of the chain values. e.g. a triange and it's upside-down variant would yield the same result.
Yes,I am okay with that.My main point is: I need to detect these shapes at any orientation (0,45,90,180,270 and even 360 degrees). Can you please briefly desribe, how can I classify my shape once,I have all my freeman chain codes.