Here , I am trying to do normalize RGB image.
Here is my code.
cv::Mat channels[3], normalize_rgb;
split(image, channels);
for (int i = 0; i < image.size().height; i++)
{
for (int j = 0; j < image.size().width; j++)
{
int b = (int)(image).at<cv::Vec3b>(i, j)[0];
int g = (int)(image).at<cv::Vec3b>(i, j)[1];
int r = (int)(image).at<cv::Vec3b>(i, j)[2];
double sum = b + g + r;
double bnorm = b / sum * 255;
double gnorm = g / sum * 255;
double rnorm = r / sum * 255;
channels[0].at<uchar>(i, j) = bnorm;
channels[1].at<uchar>(i, j) = gnorm;
channels[2].at<uchar>(i, j) = rnorm;
}
}
merge(channels, 3, normalize_rgb);
normalize = normalize_rgb.clone();
Problem: after normalizing r,g, b value is giving me very small value which turns to 0. and hence I get black image.
Anyone can please help me to figure out problems. thanks
Change image to double first. It is black because when you divide int by int you get zero. And then you're trying to set uchar = double which is completely wrong.
Try:
double bnorm = double (b) / sum * 255;
You need to divide the sum by the number of pixels.
In a 1000x1000 image you want to divide by the average, not by one million times the average.
Note that dividing by the average may give you values bigger than 255 (values higher than the average) so clamping is required after the scaling. Probably a better solution would be aiming at the average becoming 128, not 255 with
double bnorm = b * k;
double gnorm = g * k;
double rnorm = r * k;
where k is computed once per image as
double average = sum / (image.size().height*image.size().width);
double k = 127.0 / average;
but note that this can still produce values higher than 255 in output.
If you want to stretch you need to normalize with the maximum value, not with the average and in this case clamping is not needed.
I found a link which related to RGB Normalization, there is a mathematical list in the article.
So actually, u need to divide a var total, and each total is just the sum of each pixel, not the whole image(width() * height()). Maybe you should try this:
for (int i = 0; i < image.size().height; i++)
{
for (int j = 0; j < image.size().width; j++)
{
int b = (int)(image).at<cv::Vec3b>(i, j)[0];
int g = (int)(image).at<cv::Vec3b>(i, j)[1];
int r = (int)(image).at<cv::Vec3b>(i, j)[2];
int sum = b + g + r;
double bnorm = b / sum * 255;
double gnorm = g / sum * 255;
double rnorm = r / sum * 255;
channels[0].at<uchar>(i, j) = bnorm;
channels[1].at<uchar>(i, j) = gnorm;
channels[2].at<uchar>(i, j) = rnorm;
}
}
Related
I would like to get average contrast value of an image and I found working code in processing .I tried to apply this in qt-creator as in c++, however when I try to run my code I get this error:
cannot convert ‘cv::Mat’ to ‘uint8_t* {aka unsigned char*}’ in initialization
uint8_t* rowPtr = foo.row(i);<
In these parts:
uint8_t* rowPtr = foo.row(i);>
Here is the code I am trying to run;
bool normalizeRange = true; // normalize results to range of 0-1
float contrast = 0;
float brightness =0;
Mat foo = imread("1.png");
int cn = foo.channels();
Scalar_<uint8_t> bgrPixel;
for(int i = 0; i < foo.rows; i++)
{
uint8_t* rowPtr = foo.row(i);
for(int j = 0; j < foo.cols; j++)
{
bgrPixel.val[0] = rowPtr[j*cn + 0]; // B
bgrPixel.val[1] = rowPtr[j*cn + 1]; // G
bgrPixel.val[2] = rowPtr[j*cn + 2]; // R
// do something with BGR values...
}
}
brightness += (0.2126 * bgrPixel.val[2]) + (0.7152 * bgrPixel.val[1]) + (0.0722 * bgrPixel.val[0]); // scales RGB to perceived brightness
if (normalizeRange) {
brightness /= 255.0; // normalize to 0-1
}
brightness /= sizeof(bgrPixel); // average result
qDebug() << "Average brightness:" << brightness;
// find contrast by comparing average brightness with current value
for(int i = 0; i < foo.rows; i++)
{
uint8_t* rowPtr = foo.row(i);
for(int j = 0; j < foo.cols; j++)
{
bgrPixel.val[0] = rowPtr[j*cn + 0]; // B
bgrPixel.val[1] = rowPtr[j*cn + 1]; // G
bgrPixel.val[2] = rowPtr[j*cn + 2]; // R
// do something with BGR values...
}
}
float pxIntensity = (0.2126 * bgrPixel.val[2]) + (0.7152 * bgrPixel.val[1]) + (0.0722 * bgrPixel.val[2]);
if (normalizeRange) {
pxIntensity /= 255.0; // normalizes to range 0-1
}
contrast += pow((brightness - pxIntensity), 2);
contrast /= sizeof(bgrPixel);
qDebug() << "Average cotrast:" << contrast;
}
Update: I have added the java code which I would like to run in C++
boolean normalizeRange = true; // normalize results to range of 0-1
PImage img;
float brightness = 0;
float contrast = 0;
void setup() {
img = loadImage(filename);
size(img.width, img.height);
image(img, 0,0);
loadPixels(); // load pixels into array, iterate!
// find average brightness across image
for (color c : pixels) {
float r = c >> 16 & 0xFF; // extract RGB values quickly (better than red(), etc)
float g = c >> 8 & 0xFF;
float b = c & 0xFF;
brightness += (0.2126 * r) + (0.7152 * g) + (0.0722 * b); // scales RGB to perceived brightness
if (normalizeRange) {
brightness /= 255.0; // normalize to 0-1
} }
brightness /= pixels.length; // average result
println("Average brightness: " + brightness);
// find contrast by comparing average brightness with current value
for (color c : pixels) {
float r = c >> 16 & 0xFF;
float g = c >> 8 & 0xFF;
float b = c & 0xFF;
float pxIntensity = (0.2126 * r) + (0.7152 * g) + (0.0722 * b);
if (normalizeRange) {
pxIntensity /= 255.0; // normalizes to range 0-1 }
contrast += pow((brightness - pxIntensity), 2);}
contrast /= pixels.length;
println("Average contrast: " + contrast);
}
Use cv::Mat::ptr() to obtain a pointer to the specified matrix row buffer.
cv::Mat::row() constructs a new cv::Mat header for submatrix that consists of that single row instead.
Iterating raw cv::Mat buffer may be more efficient but less readable way to iterate elements. Read about different ways and their comparison here.
everyone I am trying to implement patter matching with FFT but I am not sure what the result should be (I think I am missing something even though a read a lot of stuff about the problem and tried a lot of different implementations this one is the best so far). Here is my FFT correlation function.
void fft2d(fftw_complex**& a, int rows, int cols, bool forward = true)
{
fftw_plan p;
for (int i = 0; i < rows; ++i)
{
p = fftw_plan_dft_1d(cols, a[i], a[i], forward ? FFTW_FORWARD : FFTW_BACKWARD, FFTW_ESTIMATE);
fftw_execute(p);
}
fftw_complex* t = (fftw_complex*)fftw_malloc(rows * sizeof(fftw_complex));
for (int j = 0; j < cols; ++j)
{
for (int i = 0; i < rows; ++i)
{
t[i][0] = a[i][j][0];
t[i][1] = a[i][j][1];
}
p = fftw_plan_dft_1d(rows, t, t, forward ? FFTW_FORWARD : FFTW_BACKWARD, FFTW_ESTIMATE);
fftw_execute(p);
for (int i = 0; i < rows; ++i)
{
a[i][j][0] = t[i][0];
a[i][j][1] = t[i][1];
}
}
fftw_free(t);
}
int findCorrelation(int argc, char* argv[])
{
BMP bigImage;
BMP keyImage;
BMP result;
RGBApixel blackPixel = { 0, 0, 0, 1 };
const bool swapQuadrants = (argc == 4);
if (argc < 3 || argc > 4) {
cout << "correlation img1.bmp img2.bmp" << endl;
return 1;
}
if (!keyImage.ReadFromFile(argv[1])) {
return 1;
}
if (!bigImage.ReadFromFile(argv[2])) {
return 1;
}
//Preparations
const int maxWidth = std::max(bigImage.TellWidth(), keyImage.TellWidth());
const int maxHeight = std::max(bigImage.TellHeight(), keyImage.TellHeight());
const int rowsCount = maxHeight;
const int colsCount = maxWidth;
BMP bigTemp = bigImage;
BMP keyTemp = keyImage;
keyImage.SetSize(maxWidth, maxHeight);
bigImage.SetSize(maxWidth, maxHeight);
for (int i = 0; i < rowsCount; ++i)
for (int j = 0; j < colsCount; ++j) {
RGBApixel p1;
if (i < bigTemp.TellHeight() && j < bigTemp.TellWidth()) {
p1 = bigTemp.GetPixel(j, i);
} else {
p1 = blackPixel;
}
bigImage.SetPixel(j, i, p1);
RGBApixel p2;
if (i < keyTemp.TellHeight() && j < keyTemp.TellWidth()) {
p2 = keyTemp.GetPixel(j, i);
} else {
p2 = blackPixel;
}
keyImage.SetPixel(j, i, p2);
}
//Here is where the transforms begin
fftw_complex **a = (fftw_complex**)fftw_malloc(rowsCount * sizeof(fftw_complex*));
fftw_complex **b = (fftw_complex**)fftw_malloc(rowsCount * sizeof(fftw_complex*));
fftw_complex **c = (fftw_complex**)fftw_malloc(rowsCount * sizeof(fftw_complex*));
for (int i = 0; i < rowsCount; ++i) {
a[i] = (fftw_complex*)fftw_malloc(colsCount * sizeof(fftw_complex));
b[i] = (fftw_complex*)fftw_malloc(colsCount * sizeof(fftw_complex));
c[i] = (fftw_complex*)fftw_malloc(colsCount * sizeof(fftw_complex));
for (int j = 0; j < colsCount; ++j) {
RGBApixel p1;
p1 = bigImage.GetPixel(j, i);
a[i][j][0] = (0.299*p1.Red + 0.587*p1.Green + 0.114*p1.Blue);
a[i][j][1] = 0.0;
RGBApixel p2;
p2 = keyImage.GetPixel(j, i);
b[i][j][0] = (0.299*p2.Red + 0.587*p2.Green + 0.114*p2.Blue);
b[i][j][1] = 0.0;
}
}
fft2d(a, rowsCount, colsCount);
fft2d(b, rowsCount, colsCount);
result.SetSize(maxWidth, maxHeight);
for (int i = 0; i < rowsCount; ++i)
for (int j = 0; j < colsCount; ++j) {
fftw_complex& y = a[i][j];
fftw_complex& x = b[i][j];
double u = x[0], v = x[1];
double m = y[0], n = y[1];
c[i][j][0] = u*m + n*v;
c[i][j][1] = v*m - u*n;
int fx = j;
if (fx>(colsCount / 2)) fx -= colsCount;
int fy = i;
if (fy>(rowsCount / 2)) fy -= rowsCount;
float r2 = (fx*fx + fy*fy);
const double cuttoffCoef = (maxWidth * maxHeight) / 37992.;
if (r2<128 * 128 * cuttoffCoef)
c[i][j][0] = c[i][j][1] = 0;
}
fft2d(c, rowsCount, colsCount, false);
const int halfCols = colsCount / 2;
const int halfRows = rowsCount / 2;
if (swapQuadrants) {
for (int i = 0; i < halfRows; ++i)
for (int j = 0; j < halfCols; ++j) {
std::swap(c[i][j][0], c[i + halfRows][j + halfCols][0]);
std::swap(c[i][j][1], c[i + halfRows][j + halfCols][1]);
}
for (int i = halfRows; i < rowsCount; ++i)
for (int j = 0; j < halfCols; ++j) {
std::swap(c[i][j][0], c[i - halfRows][j + halfCols][0]);
std::swap(c[i][j][1], c[i - halfRows][j + halfCols][1]);
}
}
for (int i = 0; i < rowsCount; ++i)
for (int j = 0; j < colsCount; ++j) {
const double& g = c[i][j][0];
RGBApixel pixel;
pixel.Alpha = 0;
int gInt = 255 - static_cast<int>(std::floor(g + 0.5));
pixel.Red = gInt;
pixel.Green = gInt;
pixel.Blue = gInt;
result.SetPixel(j, i, pixel);
}
BMP res;
res.SetSize(maxWidth, maxHeight);
result.WriteToFile("result.bmp");
return 0;
}
Sample output
This question would probably be more appropriately posted on another site like cross validated (metaoptimize.com used to also be a good one, but it appears to be gone)
That said:
There's two similar operations you can perform with FFT: convolution and correlation. Convolution is used for determining how two signals interact with each-other, whereas correlation can be used to express how similar two signals are to each-other. Make sure you're doing the right operation as they're both commonly implemented throught a DFT.
For this type of application of DFTs you usually wouldn't extract any useful information in the fourier spectrum unless you were looking for frequencies common to both data sources or whatever (eg, if you were comparing two bridges to see if their supports are spaced similarly).
Your 3rd image looks a lot like the power domain; normally I see the correlation output entirely grey except where overlap occurred. Your code definitely appears to be computing the inverse DFT, so unless I'm missing something the only other explanation I've come up with for the fuzzy look could be some of the "fudge factor" code in there like:
if (r2<128 * 128 * cuttoffCoef)
c[i][j][0] = c[i][j][1] = 0;
As for what you should expect: wherever there are common elements between the two images you'll see a peak. The larger the peak, the more similar the two images are near that region.
Some comments and/or recommended changes:
1) Convolution & correlation are not scale invariant operations. In other words, the size of your pattern image can make a significant difference in your output.
2) Normalize your images before correlation.
When you get the image data ready for the forward DFT pass:
a[i][j][0] = (0.299*p1.Red + 0.587*p1.Green + 0.114*p1.Blue);
a[i][j][1] = 0.0;
/* ... */
How you grayscale the image is your business (though I would've picked something like sqrt( r*r + b*b + g*g )). However, I don't see you doing anything to normalize the image.
The word "normalize" can take on a few different meanings in this context. Two common types:
normalize the range of values between 0.0 and 1.0
normalize the "whiteness" of the images
3) Run your pattern image through an edge enhancement filter. I've personally made use of canny, sobel, and I think I messed with a few others. As I recall, canny was "quick'n dirty", sobel was more expensive, but I got comparable results when it came time to do correlation. See chapter 24 of the "dsp guide" book that's freely available online. The whole book is worth your time, but if you're low on time then at a minimum chapter 24 will help a lot.
4) Re-scale the output image between [0, 255]; if you want to implement thresholds, do it after this step because the thresholding step is lossy.
My memory on this one is hazy, but as I recall (edited for clarity):
You can scale the final image pixels (before rescaling) between [-1.0, 1.0] by dividing off the largest power spectrum value from the entire power spectrum
The largest power spectrum value is, conveniently enough, the center-most value in the power spectrum (corresponding to the lowest frequency)
If you divide it off the power spectrum, you'll end up doing twice the work; since FFTs are linear, you can delay the division until after the inverse DFT pass to when you're re-scaling the pixels between [0..255].
If after rescaling most of your values end up so black you can't see them, you can use a solution to the ODE y' = y(1 - y) (one example is the sigmoid f(x) = 1 / (1 + exp(-c*x) ), for some scaling factor c that gives better gradations). This has more to do with improving your ability to interpret the results visually than anything you might use to programmatically find peaks.
edit I said [0, 255] above. I suggest you rescale to [128, 255] or some other lower bound that is gray rather than black.
I tried a quick and dirty translation of the code here.
However, my version outputs noise comparable to grey t-shirt material, or heather if it please you:
#include <fstream>
#include "perlin.h"
double Perlin::cos_Interp(double a, double b, double x)
{
ft = x * 3.1415927;
f = (1 - cos(ft)) * .5;
return a * (1 - f) + b * f;
}
double Perlin::noise_2D(double x, double y)
{
/*
int n = (int)x + (int)y * 57;
n = (n << 13) ^ n;
int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
return 1.0 - ((double)nn / 1073741824.0);
*/
int n = (int)x + (int)y * 57;
n = (n<<13) ^ n;
return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
}
double Perlin::smooth_2D(double x, double y)
{
corners = ( noise_2D(x - 1, y - 1) + noise_2D(x + 1, y - 1) + noise_2D(x - 1, y + 1) + noise_2D(x + 1, y + 1) ) / 16;
sides = ( noise_2D(x - 1, y) + noise_2D(x + 1, y) + noise_2D(x, y - 1) + noise_2D(x, y + 1) ) / 8;
center = noise_2D(x, y) / 4;
return corners + sides + center;
}
double Perlin::interp(double x, double y)
{
int x_i = int(x);
double x_left = x - x_i;
int y_i = int(y);
double y_left = y - y_i;
double v1 = smooth_2D(x_i, y_i);
double v2 = smooth_2D(x_i + 1, y_i);
double v3 = smooth_2D(x_i, y_i + 1);
double v4 = smooth_2D(x_i + 1, y_i + 1);
double i1 = cos_Interp(v1, v2, x_left);
double i2 = cos_Interp(v3, v4, x_left);
return cos_Interp(i1, i2, y_left);
}
double Perlin::perlin_2D(double x, double y)
{
double total = 0;
double p = .25;
int n = 1;
for(int i = 0; i < n; ++i)
{
double freq = pow(2, i);
double amp = pow(p, i);
total = total + interp(x * freq, y * freq) * amp;
}
return total;
}
int main()
{
Perlin perl;
ofstream ofs("./noise2D.ppm", ios_base::binary);
ofs << "P6\n" << 512 << " " << 512 << "\n255\n";
for(int i = 0; i < 512; ++i)
{
for(int j = 0; j < 512; ++j)
{
double n = perl.perlin_2D(i, j);
n = floor((n + 1.0) / 2.0 * 255);
unsigned char c = n;
ofs << c << c << c;
}
}
ofs.close();
return 0;
}
I don't believe that I strayed too far from the aforementioned site's directions aside from adding in the ppm image generation code, but then again I'll admit to not fully grasping what is going on in the code.
As you'll see by the commented section, I tried two (similar) ways of generating pseudorandom numbers for noise. I also tried different ways of scaling the numbers returned by perlin_2D to RGB color values. These two ways of editing the code have just yielded different looking t-shirt material. So, I'm forced to believe that there's something bigger going on that I am unable to recognize.
Also, I'm compiling with g++ and the c++11 standard.
EDIT: Here's an example: http://imgur.com/Sh17QjK
To convert a double in the range of [-1.0, 1.0] to an integer in range [0, 255]:
n = floor((n + 1.0) / 2.0 * 255.99);
To write it as a binary value to the PPM file:
ofstream ofs("./noise2D.ppm", ios_base::binary);
...
unsigned char c = n;
ofs << c << c << c;
Is this a direct copy of your code? You assigned an integer to what should be the Y fractional value - it's a typo and it will throw the entire noise algorithm off if you don't fix:
double Perlin::interp(double x, double y)
{
int x_i = int(x);
double x_left = x - x_i;
int y_i = int(y);
double y_left = y = y_i; //This Should have a minus, not an "=" like the line above
.....
}
My guess is if you're successfully generating the bitmap with the proper color computation, you're getting vertical bars or something along those lines?
You also need to remember that the Perlin generator usually spits out numbers in the range of -1 to 1 and you need to multiply the resultant value as such:
value * 127 + 128 = {R, G, B}
to get a good grayscale image.
I have a 3007 x 1644 dimensional matrix of terms and documents. I am trying to assign weights to frequency of terms in each document so I'm using this log entropy formula http://en.wikipedia.org/wiki/Latent_semantic_indexing#Term_Document_Matrix (See entropy formula in the last row).
I'm successfully doing this but my code is running for >7 minutes.
Here's the code:
int N = mat.cols();
for(int i=1;i<=mat.rows();i++){
double gfi = sum(mat(i,colon()))(1,1); //sum of occurrence of terms
double g =0;
if(gfi != 0){// to avoid divide by zero error
for(int j = 1;j<=N;j++){
double tfij = mat(i,j);
double pij = gfi==0?0.0:tfij/gfi;
pij = pij + 1; //avoid log0
double G = (pij * log(pij))/log(N);
g = g + G;
}
}
double gi = 1 - g;
for(int j=1;j<=N;j++){
double tfij = mat(i,j) + 1;//avoid log0
double aij = gi * log(tfij);
mat(i,j) = aij;
}
}
Anyone have ideas how I can optimize this to make it faster? Oh and mat is a RealSparseMatrix from amlpp matrix library.
UPDATE
Code runs on Linux mint with 4gb RAM and AMD Athlon II dual core
Running time before change: > 7mins
After #Kereks answer: 4.1sec
Here's a very naive rewrite that removes some redundancies:
int const N = mat.cols();
double const logN = log(N);
for (int i = 1; i <= mat.rows(); ++i)
{
double const gfi = sum(mat(i, colon()))(1, 1); // sum of occurrence of terms
double g = 0;
if (gfi != 0)
{
for (int j = 1; j <= N; ++j)
{
double const pij = mat(i, j) / gfi + 1;
g += pij * log(pij);
}
g /= logN;
}
for (int j = 1; j <= N; ++j)
{
mat(i,j) = (1 - g) * log(mat(i, j) + 1);
}
}
Also make sure that the matrix data structure is sane (e.g. a flat array accessed in strides; not a bunch of dynamically allocated rows).
Also, I think the first + 1 is a bit silly. You know that x -> x * log(x) is continuous at zero with limit zero, so you should write:
double const pij = mat(i, j) / gfi;
if (pij != 0) { g += pij + log(pij); }
In fact, you might even write the first inner for loop like this, avoiding a division when it isn't needed:
for (int j = 1; j <= N; ++j)
{
if (double pij = mat(i, j))
{
pij /= gfi;
g += pij * log(pij);
}
}
I have points in an image. I need to detect the most collinear points. The fastest method is to use Hough transform, but I have to modify the opencv method. Actually I need that the semi collinear points to be returned with detected line, for this reason I modified the polar line struct. A tolerance threshold is also needed to detect nearly detected points as shown in the image. Can someone help in how to tune this threshold?
I need at least four semi collinear points to detect the line to which they belong.
The points of first image were detected by 6 overlapped lines
the point of middle images were detected by nothing
the third's points
were detected by three lines
Which is the best way to get rid from the overlapped liens?? Or how to tune the tolerance threshold to detect the semi collinear points by only one line?
the is my own function call:
vector<CvLinePolar2> lines;
CvMat c_image = source1; // loaded image
HoughLinesStandard(&c_image,1,CV_PI/180,4,&lines,INT_MAX);
typedef struct CvLinePolar2
{
float rho;
float angle;
vector<CvPoint> points;
};
void HoughLinesStandard( const CvMat* img, float rho, float theta,
int threshold, vector<CvLinePolar2> *lines, int linesMax= INT_MAX )
{
cv::AutoBuffer<int> _accum, _sort_buf;
cv::AutoBuffer<float> _tabSin, _tabCos;
const uchar* image;
int step, width, height;
int numangle, numrho;
int total = 0;
int i, j;
float irho = 1 / rho;
double scale;
vector<vector<CvPoint>> lpoints;
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) );
//memset( lpoints, 0, sizeof(lpoints) );
lpoints.resize(sizeof(accum[0]) * (numangle+2) * (numrho+2));
float ang = 0;
for(int 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 )
{
CvPoint pt;
pt.x = j; pt.y = i;
for(int n = 0; n < numangle; n++ )
{
int r = cvRound( j * tabCos[n] + i * tabSin[n] );
r += (numrho - 1) / 2;
int ind = (n+1) * (numrho+2) + r+1;
int s = accum[ind];
accum[ind]++;
lpoints[ind].push_back(pt);
}
}
}
// stage 2. find local maximums
for(int r = 0; r < numrho; r++ )
for(int 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.points = lpoints[idx];
lines->push_back(line);
}
}
One approach is non-maximal suppression to thin out the candidate set for potential lines. Once you've identified the thinned potential lines you could then compute an average of the remaining lines that would satisfy some angular or spatial difference threshold.
Try HoughLinesP..opencv reference