what algorithm does cv::arclength use to compute perimeter? - opencv

I am currently doing a project which requires me use some structural analysis like finding the perimeter and area. I have successfully obtained the contour of the object.
when I use contour.size() function it return 1108(in this case)
when I used cv::arclength(contour) function it returns 1200.
shouldn't the Perimeter be the number of points of the contour.(the contour is the external boundary of the object)? Which should I trust?

not necessarily, with cv::arclength you summarize the euclidean distances between the consecutive points in the curve.
Here is a code snippet of cv::arclength:
...
const Point2f* ptf = curve.ptr<Point2f>();
...
for( i = 0; i < count; i++ )
{
Point2f p = ptf[i];
float dx = p.x - prev.x, dy = p.y - prev.y;
buf[j] = dx*dx + dy*dy;
if( ++j == N || i == count-1 )
{
Mat bufmat(1, j, CV_32F, buf);
sqrt(bufmat, bufmat);
for( ; j > 0; j-- )
perimeter += buf[j-1];
}
prev = p;
}
return perimeter;

Related

Converting a pointcloud to a depth/multi channel image

I have a pointcloud generated by scanning a planar surface using stereo cameras. I have generated features such as normals, fpfh etc and using this information I want to classify areas in the pointcloud. To enable the use of more traditional CNN approaches I want to convert this pointcloud to a multi-channel image in opencv. I have the pointcloud collapsed to the XY plane, and aligned to the X and Y axes so that I can create a bounding box for the image.
I am looking for ideas on how to proceed further with the mapping from points to pixels. Specifically, I am confused about the image size, and how to go about filling in each pixel with the appropriate data. (Overlapping points would be averaged out, empty ones will be labelled accordingly). Since this is an unorganized pointcloud, I do not have camera parameters to use, and I guess PCL's RangImage class would not work in my case.
Any help is appreciated!
Try creating an empty cv::Mat of predetermined size first. Then iterate through every pixel of that Mat to determine what value it should take.
Here is some code which does something similar to what you were describing:
cv::Mat makeImageFromPointCloud(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud, std::string dimensionToRemove, float stepSize1, float stepSize2)
{
pcl::PointXYZI cloudMin, cloudMax;
pcl::getMinMax3D(*cloud, cloudMin, cloudMax);
std::string dimen1, dimen2;
float dimen1Max, dimen1Min, dimen2Min, dimen2Max;
if (dimensionToRemove == "x")
{
dimen1 = "y";
dimen2 = "z";
dimen1Min = cloudMin.y;
dimen1Max = cloudMax.y;
dimen2Min = cloudMin.z;
dimen2Max = cloudMax.z;
}
else if (dimensionToRemove == "y")
{
dimen1 = "x";
dimen2 = "z";
dimen1Min = cloudMin.x;
dimen1Max = cloudMax.x;
dimen2Min = cloudMin.z;
dimen2Max = cloudMax.z;
}
else if (dimensionToRemove == "z")
{
dimen1 = "x";
dimen2 = "y";
dimen1Min = cloudMin.x;
dimen1Max = cloudMax.x;
dimen2Min = cloudMin.y;
dimen2Max = cloudMax.y;
}
std::vector<std::vector<int>> pointCountGrid;
int maxPoints = 0;
std::vector<pcl::PointCloud<pcl::PointXYZI>::Ptr> grid;
for (float i = dimen1Min; i < dimen1Max; i += stepSize1)
{
pcl::PointCloud<pcl::PointXYZI>::Ptr slice = passThroughFilter1D(cloud, dimen1, i, i + stepSize1);
grid.push_back(slice);
std::vector<int> slicePointCount;
for (float j = dimen2Min; j < dimen2Max; j += stepSize2)
{
pcl::PointCloud<pcl::PointXYZI>::Ptr grid_cell = passThroughFilter1D(slice, dimen2, j, j + stepSize2);
int gridSize = grid_cell->size();
slicePointCount.push_back(gridSize);
if (gridSize > maxPoints)
{
maxPoints = gridSize;
}
}
pointCountGrid.push_back(slicePointCount);
}
cv::Mat mat(static_cast<int>(pointCountGrid.size()), static_cast<int>(pointCountGrid.at(0).size()), CV_8UC1);
mat = cv::Scalar(0);
for (int i = 0; i < mat.rows; ++i)
{
for (int j = 0; j < mat.cols; ++j)
{
int pointCount = pointCountGrid.at(i).at(j);
float percentOfMax = (pointCount + 0.0) / (maxPoints + 0.0);
int intensity = percentOfMax * 255;
mat.at<uchar>(i, j) = intensity;
}
}
return mat;
}

How to match keypoints in SIFT ?

How to match keypoints in SIFT ?
I have calculated 128 size vector for each keypoint in an image.
let, I1 is original image, I2 is 45 degree rotated image.
I got 130 keypoints for I1 and 104 keypoints for I2.
i.e. 128x130 and 128x104.
I calculated euclidean distance between one keypoint of I1 and all keypoints of I2. so I got again euclidean distance matrix of size 128x104.
Now I need to choose nearest keypoint from this euclidean distance matrix. How I can select minimum distance 128 size vector out of 128 x 104 sized matrix?
Since you have already calculated the distance between the keypoints, in order to match them, sort them in increasing order of Euclidean distance, and consider only those keypoints which are a constant*min_distance [i.e: select on some %age of the sorted distances] as 'good matches'.
There is also BruteForceMatcher, KNNMatch and FlannBasedMatcher in OpenCV (URL Below)
http://docs.opencv.org/2.4/doc/tutorials/features2d/feature_flann_matcher/feature_flann_matcher.html#feature-flann-matcher
and
http://docs.opencv.org/2.4/modules/features2d/doc/common_interfaces_of_descriptor_matchers.html#descriptormatcher-knnmatch
Also, have a look at these questions and their responses.
1) Trying to match two images using sift in OpenCv, but too many matches
2) Efficient way for SIFT descriptor matching
Just for completeness, providing some very rough code for your reference.
If you have ;
class SIFTDemo
{
private:
Mat image;
vector<cv::KeyPoint> keypoints;
Mat descriptors;
Mat sift_output;
vector<DMatch> matches;
public:
SIFTDemo();
~SIFTDemo();
SIFTDemo(Mat m);
void extractSiftFeatures();
vector <DMatch> FindMatchesEuclidian(SIFTDemo &m2);
};
Then one can have something like this;
void SIFTDemo::extractSiftFeatures()
{
SIFT siftobject;
siftobject.operator()(image, Mat(), keypoints, descriptors);
}
vector<DMatch> SIFTDemo::FindMatchesEuclidian(SIFTDemo &m2)
{
// Calculate euclidian distance between keypoints to find best matching pairs.
// create two dimensional vector for storing euclidian distance
vector< vector<float> > vec1, unsortedvec1;
for (int i=0; i<this->keypoints.size(); i++)
{
vec1.push_back(vector<float>()); // Add an empty row
unsortedvec1.push_back(vector<float>());
}
// create vector of DMatch for storing matxhes point
vector<DMatch> matches1;
DMatch dm1;
// loop through keypoints1.size
for (int i=0; i<this->keypoints.size(); i++)
{
// get 128 dimensions in a vector
vector<float> k1;
for(int x=0; x<128; x++)
{
k1.push_back((float)this->descriptors.at<float>(i,x));
}
// loop through keypoints2.size
for (int j=0; j<m2.keypoints.size(); j++)
{
double temp=0;
// calculate euclidian distance
for(int x=0; x<128; x++)
{
temp += (pow((k1[x] - (float)m2.descriptors.at<float>(j,x)), 2.0));
}
vec1[i].push_back((float)sqrt(temp)); // store distance for each keypoints in image2
unsortedvec1[i] = vec1[i];
}
sort(vec1[i].begin(),vec1[i].end()); // sort the vector distances to get shortest distance
// find position of the shortest distance
int pos = (int)(find(unsortedvec1[i].begin(), unsortedvec1[i].end(), vec1[i][0]) - unsortedvec1[i].begin());
// assign that matchin feature to DMatch variable dm1
dm1.queryIdx = i;
dm1.trainIdx = pos;
dm1.distance = vec1[i][0];
matches1.push_back(dm1);
this->matches.push_back(dm1);
//cout << pos << endl;
}
// craete two dimensional vector for storing euclidian distance
vector<vector<float>> vec2, unsortedvec2;
for (int i=0; i<m2.keypoints.size(); i++)
{
vec2.push_back(vector<float>()); // Add an empty row
unsortedvec2.push_back(vector<float>());
}
// create vector of DMatch for storing matxhes point
vector<DMatch> matches2;
DMatch dm2;
// loop through keypoints2.size
for (int i=0; i<m2.keypoints.size(); i++)
{
// get 128 dimensions in a vector
vector<float> k1;
for(int x=0; x<128; x++)
{
k1.push_back((float)m2.descriptors.at<float>(i,x));
}
// loop through keypoints1.size
for (int j=0; j<this->keypoints.size(); j++)
{
double temp=0;
// calculate euclidian distance
for(int x=0; x<128; x++)
{
temp += (pow((k1[x] - (float)this->descriptors.at<float>(j,x)), 2.0));
}
vec2[i].push_back((float)sqrt(temp)); // store distance for each keypoints in image1
unsortedvec2[i] = vec2[i];
}
sort(vec2[i].begin(),vec2[i].end()); // sort the vector distances to get shortest distance
// find position of the shortest distance
int pos = (int)(find(unsortedvec2[i].begin(), unsortedvec2[i].end(), vec2[i][0]) - unsortedvec2[i].begin());
// assign that matchin feature to DMatch variable
dm2.queryIdx = i;
dm2.trainIdx = pos;
dm2.distance = vec2[i][0];
matches2.push_back(dm2);
m2.matches.push_back(dm2);
//cout << pos << endl;
}
// Ref : http://docs.opencv.org/2.4/doc/tutorials/features2d/feature_flann_matcher/feature_flann_matcher.html#feature-flann-matcher
//-- Quick calculation of max and min distances between keypoints1
double max_dist = 0;
double min_dist = 500.0;
for( int i = 0; i < matches1.size(); i++ )
{
double dist = matches1[i].distance;
if( dist < min_dist ) min_dist = dist;
if( dist > max_dist ) max_dist = dist;
}
// Draw only "good" matches1 (i.e. whose distance is less than 2*min_dist )
vector<DMatch> good_matches1;
for( int i = 0; i < matches1.size(); i++ )
{
if( matches1[i].distance <= 2*min_dist )
{
good_matches1.push_back( matches1[i]);
}
}
// Quick calculation of max and min distances between keypoints2 but not used
for( int i = 0; i < matches2.size(); i++ )
{
double dist = matches2[i].distance;
if( dist < min_dist ) min_dist = dist;
if( dist > max_dist ) max_dist = dist;
}
// Draw only "good" matches by comparing that (ft1 gives ft2) and (ft2 gives ft1)
vector<DMatch> good_matches;
for(unsigned int i=0; i<good_matches1.size(); i++)
{
// check ft1=ft2 and ft2=ft1
if(good_matches1[i].queryIdx == matches2[good_matches1[i].trainIdx].trainIdx)
good_matches.push_back(good_matches1[i]);
}
return good_matches;
}
FInally, as mentioned in the comment also look at RANSAC to do this. Not diving into that not to make the answer longer but you can find resources online and on SO.

How to draw Optical flow images from ocl::PyrLKOpticalFlow::dense()

How to draw Optical flow images from ocl::PyrLKOpticalFlow::dense() Which actually calculates both horizontal and vertical component of the Optical flow? So I don't know how to draw them. I'm new to opencv . Can anyone help me?
Syntax :
ocl::PyrLKOpticalFlow::dense(oclMat &prevImg, oclMat& nextImg, oclMat& u, oclMat &v,oclMat &err)
A well establische method used in the optical flow community is to display a motion vector field as a color coded image as you can see at one of the various data sets. E.g MPI dataset or the Middlebury dataset.
Therefor you estimate the length and the angle of your motion vector. And use a HSV to RGB colorspace transformation (see OpenCV cvtColor function) to create your color coded image. Use the angle of your motion vector as H (Hue) - channel and the normalized length as the S (Saturation) - channel and set V (Value) to 1. The the color of your image will show you the direction of your motion and the saturation the length ( speed ).
The code will should like this ( Note if use_value == true, the Saturation will be set to 1 and the Value channel is related to the motion vector length):
void FlowToRGB(const cv::Mat & inpFlow,
cv::Mat & rgbFlow,
const float & max_size ,
bool use_value)
{
if(inpFlow.empty()) return;
if( inpFlow.depth() != CV_32F)
throw(std::exception("FlowToRGB: error inpFlow wrong data type ( has be CV_32FC2"));
const float grad2deg = (float)(90/3.141);
cv::Mat pol(inpFlow.size(), CV_32FC2);
float mean_val = 0, min_val = 1000, max_val = 0;
float _dx, _dy;
for(int r = 0; r < inpFlow.rows; r++)
{
for(int c = 0; c < inpFlow.cols; c++)
{
cv::Point2f polar = cvmath::toPolar(inpFlow.at<cv::Point2f>(r,c));
polar.y *= grad2deg;
mean_val +=polar.x;
max_val = MAX(max_val, polar.x);
min_val = MIN(min_val, polar.x);
pol.at<cv::Point2f>(r,c) = cv::Point2f(polar.y,polar.x);
}
}
mean_val /= inpFlow.size().area();
float scale = max_val - min_val;
float shift = -min_val;//-mean_val + scale;
scale = 255.f/scale;
if( max_size > 0)
{
scale = 255.f/max_size;
shift = 0;
}
//calculate the angle, motion value
cv::Mat hsv(inpFlow.size(), CV_8UC3);
uchar * ptrHSV = hsv.ptr<uchar>();
int idx_val = (use_value) ? 2:1;
int idx_sat = (use_value) ? 1:2;
for(int r = 0; r < inpFlow.rows; r++, ptrHSV += hsv.step1())
{
uchar * _ptrHSV = ptrHSV;
for(int c = 0; c < inpFlow.cols; c++, _ptrHSV+=3)
{
cv::Point2f vpol = pol.at<cv::Point2f>(r,c);
_ptrHSV[0] = cv::saturate_cast<uchar>(vpol.x);
_ptrHSV[idx_val] = cv::saturate_cast<uchar>( (vpol.y + shift) * scale);
_ptrHSV[idx_sat] = 255;
}
}
cv::Mat rgbFlow32F;
cv::cvtColor(hsv, rgbFlow32F, CV_HSV2BGR);
rgbFlow32F.convertTo(rgbFlow, CV_8UC3);}
}
Python
Please refer to opt_flow.py#draw_flow
def draw_flow(img, flow, step=16):
h, w = img.shape[:2]
y, x = np.mgrid[step/2:h:step, step/2:w:step].reshape(2,-1).astype(int)
fx, fy = flow[y,x].T
lines = np.vstack([x, y, x+fx, y+fy]).T.reshape(-1, 2, 2)
lines = np.int32(lines + 0.5)
vis = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
cv2.polylines(vis, lines, 0, (0, 255, 0))
for (x1, y1), (x2, y2) in lines:
cv2.circle(vis, (x1, y1), 1, (0, 255, 0), -1)
return vis
C++
Please can refer to tvl1_optical_flow.cpp#drawOpticalFlow
static void drawOpticalFlow(const Mat_<Point2f>& flow, Mat& dst, float maxmotion = -1)
{
dst.create(flow.size(), CV_8UC3);
dst.setTo(Scalar::all(0));
// determine motion range:
float maxrad = maxmotion;
if (maxmotion <= 0)
{
maxrad = 1;
for (int y = 0; y < flow.rows; ++y)
{
for (int x = 0; x < flow.cols; ++x)
{
Point2f u = flow(y, x);
if (!isFlowCorrect(u))
continue;
maxrad = max(maxrad, sqrt(u.x * u.x + u.y * u.y));
}
}
}
for (int y = 0; y < flow.rows; ++y)
{
for (int x = 0; x < flow.cols; ++x)
{
Point2f u = flow(y, x);
if (isFlowCorrect(u))
dst.at<Vec3b>(y, x) = computeColor(u.x / maxrad, u.y / maxrad);
}
}
}
I did something like this in my code, a while ago:
calcOpticalFlowPyrLK(frame_prec,frame_cur,v_corners_prec[i],corners_cur,status, err);
for(int j=0; j<corners_cur.size(); j++){
if(status[j]){
line(frame_cur,v_corners_prec[i][j],corners_cur[j],colors[i]);
}
}
Basically I draw a line between the points tracked by the OF in this iteration and the previous ones, this draws the optical flow lines which represent the flow on the image.
Hope this helps..

Search for lines with a small range of angles in OpenCV

I'm using the Hough transform in OpenCV to detect lines. However, I know in advance that I only need lines within a very limited range of angles (about 10 degrees or so). I'm doing this in a very performance sensitive setting, so I'd like to avoid the extra work spent detecting lines at other angles, lines I know in advance I don't care about.
I could extract the Hough source from OpenCV and just hack it to take min_rho and max_rho parameters, but I'd like a less fragile approach (have to manually update my code w/ each OpenCV update, etc.).
What's the best approach here?
Well, i've modified the icvHoughlines function to go for a certain range of angles. I'm sure there's cleaner ways that plays with memory allocation as well, but I got a speed gain going from 100ms to 33ms for a range of angle going from 180deg to 60deg, so i'm happy with that.
Note that this code also outputs the accumulator value. Also, I only output 1 line because that fit my purposes but there was no gain really there.
static void
icvHoughLinesStandard2( const CvMat* img, float rho, float theta,
int threshold, CvSeq *lines, int linesMax )
{
cv::AutoBuffer<int> _accum, _sort_buf;
cv::AutoBuffer<float> _tabSin, _tabCos;
const uchar* image;
int step, width, height;
int numangle, numrho;
int total = 0;
float ang;
int r, n;
int i, j;
float irho = 1 / rho;
double scale;
CV_Assert( CV_IS_MAT(img) && CV_MAT_TYPE(img->type) == CV_8UC1 );
image = img->data.ptr;
step = img->step;
width = img->cols;
height = img->rows;
numangle = cvRound(CV_PI / theta);
numrho = cvRound(((width + height) * 2 + 1) / rho);
_accum.allocate((numangle+2) * (numrho+2));
_sort_buf.allocate(numangle * numrho);
_tabSin.allocate(numangle);
_tabCos.allocate(numangle);
int *accum = _accum, *sort_buf = _sort_buf;
float *tabSin = _tabSin, *tabCos = _tabCos;
memset( accum, 0, sizeof(accum[0]) * (numangle+2) * (numrho+2) );
// find n and ang limits (in our case we want 60 to 120
float limit_min = 60.0/180.0*PI;
float limit_max = 120.0/180.0*PI;
//num_steps = (limit_max - limit_min)/theta;
int start_n = floor(limit_min/theta);
int stop_n = floor(limit_max/theta);
for( ang = limit_min, n = start_n; n < stop_n; ang += theta, n++ )
{
tabSin[n] = (float)(sin(ang) * irho);
tabCos[n] = (float)(cos(ang) * irho);
}
// stage 1. fill accumulator
for( i = 0; i < height; i++ )
for( j = 0; j < width; j++ )
{
if( image[i * step + j] != 0 )
//
for( n = start_n; n < stop_n; n++ )
{
r = cvRound( j * tabCos[n] + i * tabSin[n] );
r += (numrho - 1) / 2;
accum[(n+1) * (numrho+2) + r+1]++;
}
}
int max_accum = 0;
int max_ind = 0;
for( r = 0; r < numrho; r++ )
{
for( n = start_n; n < stop_n; n++ )
{
int base = (n+1) * (numrho+2) + r+1;
if (accum[base] > max_accum)
{
max_accum = accum[base];
max_ind = base;
}
}
}
CvLinePolar2 line;
scale = 1./(numrho+2);
int idx = max_ind;
n = cvFloor(idx*scale) - 1;
r = idx - (n+1)*(numrho+2) - 1;
line.rho = (r - (numrho - 1)*0.5f) * rho;
line.angle = n * theta;
line.votes = accum[idx];
cvSeqPush( lines, &line );
}
If you use the Probabilistic Hough transform then the output is in the form of a cvPoint each for lines[0] and lines[1] parameters. We can get x and y co-ordinated for each of the two points by pt1.x, pt1.y and pt2.x and pt2.y.
Then use the simple formula for finding slope of a line - (y2-y1)/(x2-x1). Taking arctan (tan inverse) of that will yield that angle in radians. Then simply filter out desired angles from the values for each hough line obtained.
I think it's more natural to use standart HoughLines(...) function, which gives collection of lines directly in rho and theta terms and select nessessary angle range from it, rather than recalculate angle from segment end points.

OpenCV: get Hough accumulator value?

Is it possible to get the accumulator value along with rho and theta from a Hough transform?
I ask because I'd like to differentiate between lines which are "well defined" (ie, which have a high accumulator value) and lines which aren't as well defined.
Thanks!
Ok, so looking at the cvhough.cpp file, the structure CvLinePolar is only defined by rho and angle.
This is all that is passed back as a result of our call to HoughLines. I am in the process of modifying the c++ file and see if i can get the votes out.
Update oct 26: just realized these are not really answers but more like questions. apparently frowned upon. I found some instructions on recompiling OpenCV. I guess we'll have to go in the code and modify it and recompile.
How to install OpenCV 2.0 on win32
update Oct 27: well, i failed at compiling the dlls for OpenCV with my new code so I ended up copy-pasting the specific parts I want to modify into my own files.
I like to add new functions so to avoid overloading the already defined functions.
There are 4 main things you need to copy over:
1- some random defines
#define hough_cmp_gt(l1,l2) (aux[l1] > aux[l2])
static CV_IMPLEMENT_QSORT_EX( icvHoughSortDescent32s, int, hough_cmp_gt, const int* )
2- redefining the struct for line parameters
typedef struct CvLinePolar2
{
float rho;
float angle;
float votes;
}
CvLinePolar2;
3- the main function that was modified
static void
icvHoughLinesStandard2( const CvMat* img, float rho, float theta,
int threshold, CvSeq *lines, int linesMax )
{
cv::AutoBuffer<int> _accum, _sort_buf;
cv::AutoBuffer<float> _tabSin, _tabCos;
const uchar* image;
int step, width, height;
int numangle, numrho;
int total = 0;
float ang;
int r, n;
int i, j;
float irho = 1 / rho;
double scale;
CV_Assert( CV_IS_MAT(img) && CV_MAT_TYPE(img->type) == CV_8UC1 );
image = img->data.ptr;
step = img->step;
width = img->cols;
height = img->rows;
numangle = cvRound(CV_PI / theta);
numrho = cvRound(((width + height) * 2 + 1) / rho);
_accum.allocate((numangle+2) * (numrho+2));
_sort_buf.allocate(numangle * numrho);
_tabSin.allocate(numangle);
_tabCos.allocate(numangle);
int *accum = _accum, *sort_buf = _sort_buf;
float *tabSin = _tabSin, *tabCos = _tabCos;
memset( accum, 0, sizeof(accum[0]) * (numangle+2) * (numrho+2) );
for( ang = 0, n = 0; n < numangle; ang += theta, n++ )
{
tabSin[n] = (float)(sin(ang) * irho);
tabCos[n] = (float)(cos(ang) * irho);
}
// stage 1. fill accumulator
for( i = 0; i < height; i++ )
for( j = 0; j < width; j++ )
{
if( image[i * step + j] != 0 )
for( n = 0; n < numangle; n++ )
{
r = cvRound( j * tabCos[n] + i * tabSin[n] );
r += (numrho - 1) / 2;
accum[(n+1) * (numrho+2) + r+1]++;
}
}
// stage 2. find local maximums
for( r = 0; r < numrho; r++ )
for( n = 0; n < numangle; n++ )
{
int base = (n+1) * (numrho+2) + r+1;
if( accum[base] > threshold &&
accum[base] > accum[base - 1] && accum[base] >= accum[base + 1] &&
accum[base] > accum[base - numrho - 2] && accum[base] >= accum[base + numrho + 2] )
sort_buf[total++] = base;
}
// stage 3. sort the detected lines by accumulator value
icvHoughSortDescent32s( sort_buf, total, accum );
// stage 4. store the first min(total,linesMax) lines to the output buffer
linesMax = MIN(linesMax, total);
scale = 1./(numrho+2);
for( i = 0; i < linesMax; i++ )
{
CvLinePolar2 line;
int idx = sort_buf[i];
int n = cvFloor(idx*scale) - 1;
int r = idx - (n+1)*(numrho+2) - 1;
line.rho = (r - (numrho - 1)*0.5f) * rho;
line.angle = n * theta;
line.votes = accum[idx];
cvSeqPush( lines, &line );
}
cvFree( (void**)&sort_buf );
cvFree( (void**)&accum );
cvFree( (void**)&tabSin );
cvFree( (void**)&tabCos);
}
4- the function that calls that function
CV_IMPL CvSeq*
cvHoughLines3( CvArr* src_image, void* lineStorage, int method,
double rho, double theta, int threshold,
double param1, double param2 )
{
CvSeq* result = 0;
CvMat stub, *img = (CvMat*)src_image;
CvMat* mat = 0;
CvSeq* lines = 0;
CvSeq lines_header;
CvSeqBlock lines_block;
int lineType, elemSize;
int linesMax = INT_MAX;
int iparam1, iparam2;
img = cvGetMat( img, &stub );
if( !CV_IS_MASK_ARR(img))
CV_Error( CV_StsBadArg, "The source image must be 8-bit, single-channel" );
if( !lineStorage )
CV_Error( CV_StsNullPtr, "NULL destination" );
if( rho <= 0 || theta <= 0 || threshold <= 0 )
CV_Error( CV_StsOutOfRange, "rho, theta and threshold must be positive" );
if( method != CV_HOUGH_PROBABILISTIC )
{
lineType = CV_32FC3;
elemSize = sizeof(float)*3;
}
else
{
lineType = CV_32SC4;
elemSize = sizeof(int)*4;
}
if( CV_IS_STORAGE( lineStorage ))
{
lines = cvCreateSeq( lineType, sizeof(CvSeq), elemSize, (CvMemStorage*)lineStorage );
}
else if( CV_IS_MAT( lineStorage ))
{
mat = (CvMat*)lineStorage;
if( !CV_IS_MAT_CONT( mat->type ) || (mat->rows != 1 && mat->cols != 1) )
CV_Error( CV_StsBadArg,
"The destination matrix should be continuous and have a single row or a single column" );
if( CV_MAT_TYPE( mat->type ) != lineType )
CV_Error( CV_StsBadArg,
"The destination matrix data type is inappropriate, see the manual" );
lines = cvMakeSeqHeaderForArray( lineType, sizeof(CvSeq), elemSize, mat->data.ptr,
mat->rows + mat->cols - 1, &lines_header, &lines_block );
linesMax = lines->total;
cvClearSeq( lines );
}
else
CV_Error( CV_StsBadArg, "Destination is not CvMemStorage* nor CvMat*" );
iparam1 = cvRound(param1);
iparam2 = cvRound(param2);
switch( method )
{
case CV_HOUGH_STANDARD:
icvHoughLinesStandard2( img, (float)rho,
(float)theta, threshold, lines, linesMax );
break;
default:
CV_Error( CV_StsBadArg, "Unrecognized method id" );
}
if( mat )
{
if( mat->cols > mat->rows )
mat->cols = lines->total;
else
mat->rows = lines->total;
}
else
result = lines;
return result;
}
And i guess you could uninstall opencv so it takes off all those automatic path setting and recompile it yourself using the CMake method and then the OpenCV is really whatever you make it.
Although this is an old question, I had the same problem, so I might as well put up my solution. The threshold in houghlines() returns 1 for any point that cleared the threshold for votes. The solution is to run houghlines() for every threshold value (until there are no more votes) and add up the votes in another array. In python (maybe with other languages too) when you have no more votes, it throws an error, so use try/except.
Here is an example in python. The array I used was for rho values of -199 to 200 with a max vote of less than 100. You can play around with those constants to suit your needs. You may need to add a line to convert the source image to grayscale.
import matplotlib.pyplot as plt
import cv2
import math
############ make houghspace array ############
houghspace = []
c = 0
height = 400
while c <= height:
houghspace.append([])
cc = 0
while cc <= 180:
houghspace[c].append(0)
cc += 1
c+=1
############ do transform ############
degree_tick = 1 #by how many degrees to check
total_votes = 1 #votes counter
highest_vote = 0 #highest vote in the array
while total_votes < 100:
img = cv2.imread('source.pgm')
edges = cv2.Canny(img,50,150,apertureSize = 3)
lines = cv2.HoughLines(edges,1,math.pi*degree_tick/180,total_votes)
try:
for rho,theta in lines[0]:
a = math.cos(theta)
b = math.sin(theta)
x1 = int((a*rho) + 1000*(-b))
y1 = int((b*rho) + 1000*(a))
x2 = int((a*rho) - 1000*(-b))
y2 = int((b*rho) - 1000*(a))
cv2.line(img,(x1,y1),(x2,y2),(50,200,255),2)
#################add votes into the array################
deradian = 180/math.pi #used to convert to degrees
for rho,theta in lines[0]:
degree = int(round(theta*deradian))
rho_pos = int(rho - 200)
houghspace[rho_pos][degree] += 1
#when lines[0] has no votes, it throws an error which is caught here
except:
total_votes = 999 #exit loop
highest_vote = total_votes
total_votes += 1
del lines
########### loop finished ###############################
print highest_vote
#############################################################
################### plot the houghspace ###################
maxy = 200 #used to offset the y-axis
miny = -200 #used to offset the y-axis
#the main graph
fig = plt.figure(figsize=(10, 5))
ax = fig.add_subplot(111)
ax.set_title('Houghspace')
plt.imshow(houghspace, cmap='gist_stern')
ax.set_aspect('equal')
plt.yticks([0,-miny,maxy-miny], [miny,0,maxy])
#the legend
cax = fig.add_axes([0, 0.1, 0.78, 0.8])
cax.get_xaxis().set_visible(False)
cax.get_yaxis().set_visible(False)
cax.patch.set_alpha(0)
cax.set_frame_on(False)
plt.colorbar(orientation='vertical')
#plot
plt.show()

Resources