JavaCV cvApproxPoly method call error - javacv

Im working in JavaCV and im trying to detect rectangle skewed by perspective and fix the image to right perspective using 4 corners of a rectangle.
I have this code:
CvSeq corners_seq = new CvSeq();
int count = 0;
for (int i = 0; i < table_lines.length; i++)
{
for (int j = i + 1; j < table_lines.length; j++)
{
CvPoint pt = HelperClass.ComputeIntersection(table_lines[i][0],table_lines[i][1], table_lines[j][0],table_lines[j][1]);
if (pt.x() >= 0 && pt.y() >= 0)
{
corners_seq.put(pt);
}
}
}
CvMemStorage corners_storage = cvCreateMemStorage(0);
CvSeq corners = cvApproxPoly(corners_seq, corners_seq.header_size(), corners_storage, CV_POLY_APPROX_DP, 8, 0);
And at cvApproxPoly i get error from native method:
Exception in thread "main" java.lang.RuntimeException: ..\..\..\src\opencv\modules\imgproc\src\utils.cpp:54: error: (-5) Input array is not a valid matrix at com.googlecode.javacv.cpp.opencv_imgproc.cvApproxPoly(Native Method)
What am i doing wrong? As i understand it, the input argument is Pointer to CvSeq

CvMemStorage storage = cvCreateMemStorage(0);
CvSeq cvSeq = cvCreateSeq(0, Loader.sizeof(CvContour.class), Loader.sizeof(CvSeq.class), storage);

Related

MPSImageIntegral returning all zeros

I am trying to use MPSImageIntegral to calculate the sum of some elements in an MTLTexture. This is what I'm doing:
std::vector<float> integralSumData;
for(int i = 0; i < 10; i++)
integralSumData.push_back((float)i);
MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR32Float
width:(integralSumData.size()) height:1 mipmapped:NO];
textureDescriptor.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
id<MTLTexture> texture = [_device newTextureWithDescriptor:textureDescriptor];
// Calculate the number of bytes per row in the image.
NSUInteger bytesPerRow = integralSumData.size() * sizeof(float);
MTLRegion region =
{
{ 0, 0, 0 }, // MTLOrigin
{integralSumData.size(), 1, 1} // MTLSize
};
// Copy the bytes from the data object into the texture
[texture replaceRegion:region
mipmapLevel:0
withBytes:integralSumData.data()
bytesPerRow:bytesPerRow];
MTLTextureDescriptor *textureDescriptor2 = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatR32Float
width:(integralSumData.size()) height:1 mipmapped:NO];
textureDescriptor2.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite;
id<MTLTexture> outtexture = [_device newTextureWithDescriptor:textureDescriptor2];
// Create a MPS filter.
MPSImageIntegral *integral = [[MPSImageIntegral alloc] initWithDevice: _device];
MPSOffset offset = { 0,0,0};
[integral setOffset:offset];
[integral setEdgeMode:MPSImageEdgeModeZero];
[integral encodeToCommandBuffer:commandBuffer sourceTexture:texture destinationTexture:outtexture];
[commandBuffer commit];
[commandBuffer waitUntilCompleted];
But, when I check my outtexture values, its all zeroes. Am I doing something wrong? Is this a correct way in which I shall use MPSImageIntegral?
I'm using the following code to read values written into the outTexture:
float outData[100];
[outtexture getBytes:outData bytesPerRow:bytesPerRow fromRegion:region mipmapLevel:0];
for(int i = 0; i < 100; i++)
std::cout << outData[i] << "\n";
Thanks
As pointed out by #Matthijis: All I had to do was use an MTLBlitEncoder to make sure I synchronise my MTLTexture before reading it into CPU, and it worked like charm!

Issue in plotting resultant bit map of two bit maps difference

I want to compare one bitmap with another bitmap (reference bitmap) and draw all the difference of it in resultant bit map.
Using below code I am able to draw only difference area but not with exact color of it.
Here is my code
Bitmap ResultantBitMap = new Bitmap(bitMap1.Height, bitMap2.Height);
BitmapData bitMap1Data = bitMap1.LockBits(new Rectangle(0, 0, bitMap1.Width, bitMap1.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
BitmapData bitMap2Data = bitMap2.LockBits(new Rectangle(0, 0, bitMap2.Width, bitMap2.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
BitmapData bitMapResultantData = ResultantBitMap.LockBits(new Rectangle(0, 0, ResultantBitMap.Width, ResultantBitMap.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
IntPtr scan0 = bitMap1Data.Scan0;
IntPtr scan02 = bitMap2Data.Scan0;
IntPtr scan0ResImg1 = bitMapResultantData.Scan0;
int bitMap1Stride = bitMap1Data.Stride;
int bitMap2Stride = bitMap2Data.Stride;
int ResultantImageStride = bitMapResultantData.Stride;
for (int y = 0; y < bitMap1.Height; y++)
{
//define the pointers inside the first loop for parallelizing
byte* p = (byte*)scan0.ToPointer();
p += y * bitMap1Stride;
byte* p2 = (byte*)scan02.ToPointer();
p2 += y * bitMap2Stride;
byte* pResImg1 = (byte*)scan0ResImg1.ToPointer();
pResImg1 += y * ResultantImageStride;
for (int x = 0; x < bitMap1.Width; x++)
{
//always get the complete pixel when differences are found
if (Math.Abs(p[0] - p2[0]) >= 20 || Math.Abs(p[1] - p2[1]) >= 20 || Math.Abs(p[2] - p2[2]) >= 20)
{
pResImg1[0] = p2[0];// B
pResImg1[1] = p2[1];//R
pResImg1[2] = p2[2];//G
pResImg1[3] = p2[3];//A (Opacity)
}
p += 4;
p2 += 4;
pResImg1 += 4;
}
}
bitMap1.UnlockBits(bitMap1Data);
bitMap2.UnlockBits(bitMap2Data);
ResultantBitMap.UnlockBits(bitMapResultantData);
ResultantBitMap.Save(#"c:\\abcd\abcd.jpeg");
What I want is the difference image with exact color of the reference image.
It's hard to tell what's going on without knowing what all those library calls and "+= 4" are but, are you sure p and p2 correspond to the first and second images of your diagram?
Also, your "Format32bppArgb" format suggests that [0] corresponds to alpha, not to red. Maybe there's a problem with that, too.

Loop Algorithm design

Hi i written a code to draw a circles using putpixel method in java.
i tried to design a loop for this code but i didn't success.
This is the original code:
g2d=(Graphics2D) g;
int x=200, y=200,rad =120;
printcircle(x,y,rad,g);
printcircle(x+rad/2,y,rad/2,g);
printcircle(x-rad/2,y,rad/2,g);
printcircle(200-90,200,30,g);
printcircle(200+90,200,30,g);
printcircle(200-30,200,30,g);
printcircle(200+30,200,30,g);
printcircle(200+45,200,15,g);
printcircle(200-45,200,15,g);
printcircle(200+15,200,15,g);
printcircle(200-15,200,15,g);
printcircle(200-15,200,15,g);
printcircle(200-75,200,15,g);
printcircle(200+75,200,15,g);
printcircle(200+105,200,15,g);
printcircle(200-105,200,15,g);
Where rad stands for radius and x,y is the center point for circles.
this is the shape that i had written my code for it
and this is the code that i had start to code it with loop:
g2d=(Graphics2D) g;
int x=200, y=200,rad =120;
printcircle(x,y,rad,g);
for(int i=0;i<2;i++)
{ int t=rad/2;
printcircle(x+t,y,t,g);
printcircle(x-t,y,t,g);
}
for(int i=0;i<3;i++)
{
int t=rad/4;
printcircle(200-90,200,30,g);
printcircle(200+90,200,30,g);
printcircle(200-30,200,30,g);
printcircle(200+30,200,30,g);
}
printcircle(200+45,200,15,g);
printcircle(200-45,200,15,g);
printcircle(200+15,200,15,g);
printcircle(200-15,200,15,g);
printcircle(200-15,200,15,g);
printcircle(200-75,200,15,g);
printcircle(200+75,200,15,g);
printcircle(200+105,200,15,g);
printcircle(200-105,200,15,g);
If anyone can help me please.
g2d=(Graphics2D) g;
int x=200, y=200,rad =120;
for(int i=0;i<8;i++)
{
int param;
if(i == 2 || i == 6)
param = 30;
else if(i == 4)
param = 60;
else if(i == 0)
param = 120;
else
param = 15;
printcircle(x+i*15,y,param,g);
if(i == 0)
continue;
printcircle(x-i*15,y,param,g);
}

Parallelizing with OpenMP - how?

I want to parallelize an OpenMP raytracing algorithm that contains two for loops.
Is there anything more I can do than just setting omp_set_num_threads(omp_get_max_threads()) and putting #pragma omp parallel for in front of the first for loop?
So far I've reached a 2.13-times faster algorithm.
Code:
start = omp_get_wtime();
#pragma omp parallel for
for (int i = 0; i < (viewport.xvmax - viewport.xvmin); i++)
{
for (int j = 0; j < (viewport.yvmax - viewport.yvmin); j++)
{
int intersection_object = -1; // none
int reflected_intersection_object = -1; // none
double current_lambda = 0x7fefffffffffffff; // maximum positive double
double current_reflected_lambda = 0x7fefffffffffffff; // maximum positive double
RAY ray, shadow_ray, reflected_ray;
PIXEL pixel;
SPHERE_INTERSECTION intersection, current_intersection, shadow_ray_intersection, reflected_ray_intersection, current_reflected_intersection;
double red, green, blue;
double theta, reflected_theta;
bool bShadow = false;
pixel.i = i;
pixel.j = j;
// 1. compute ray:
compute_ray(&ray, &view_point, &viewport, &pixel, &camera_frame, focal_distance);
// 2. check if ray hits an object:
for (int k = 0; k < NSPHERES; k++)
{
if (sphere_intersection(&ray, &sphere[k], &intersection))
{
// there is an intersection between ray and object
// 1. Izracunanaj normalu...
intersection_normal(&sphere[k], &intersection, &ray);
// 2. ako je lambda presjecista manji od trenutacnog:
if (intersection.lambda_in < current_lambda)
{
current_lambda = intersection.lambda_in;
intersection_object = k;
copy_intersection_struct(&current_intersection, &intersection);
}
// izracunaj current lambda current_lambda =
// oznaci koji je trenutacni object : intersection_object =
// kopiraj strukturu presjeka : copy_intersection_struct();
}
}
// Compute the color of the pixel:
if (intersection_object > -1)
{
compute_shadow_ray(&shadow_ray, &intersection, &light);
theta = dotproduct(&(shadow_ray.direction), &(intersection.normal));
for (int l = 0; l<NSPHERES; l++)
{
if (l != intersection_object)
{
if (sphere_intersection(&shadow_ray, &sphere[l], &shadow_ray_intersection) && (theta>0.0))
bShadow = true;
}
}
if (bShadow)
{ // if in shadow, add only ambiental light to the surface color
red = shadow(sphere[intersection_object].ka_rgb[CRED], ambi_light_intensity);
green = shadow(sphere[intersection_object].ka_rgb[CGREEN], ambi_light_intensity);
blue = shadow(sphere[intersection_object].ka_rgb[CBLUE], ambi_light_intensity);
}
else
{
// the intersection is not in shadow:
red = blinnphong_shading(&current_intersection, &light, &view_point,
sphere[intersection_object].kd_rgb[CRED], sphere[intersection_object].ks_rgb[CRED], sphere[intersection_object].ka_rgb[CRED], sphere[intersection_object].shininess,
light_intensity, ambi_light_intensity);
green = blinnphong_shading(&current_intersection, &light, &view_point,
sphere[intersection_object].kd_rgb[CGREEN], sphere[intersection_object].ks_rgb[CGREEN], sphere[intersection_object].ka_rgb[CGREEN], sphere[intersection_object].shininess,
light_intensity, ambi_light_intensity);
blue = blinnphong_shading(&current_intersection, &light, &view_point,
sphere[intersection_object].kd_rgb[CBLUE], sphere[intersection_object].ks_rgb[CBLUE], sphere[intersection_object].ka_rgb[CBLUE], sphere[intersection_object].shininess,
light_intensity, ambi_light_intensity);
}
tabelaPixlov[i][j].red = red;
tabelaPixlov[i][j].green = green;
tabelaPixlov[i][j].blue = blue;
glColor3f(tabelaPixlov[i][j].red, tabelaPixlov[i][j].green, tabelaPixlov[i][j].blue);
intersection_object = -1;
bShadow = false;
}
else
{
// draw the pixel with the background color
tabelaPixlov[i][j].red = 0;
tabelaPixlov[i][j].green = 0;
tabelaPixlov[i][j].blue = 0;
intersection_object = -1;
bShadow = false;
}
current_lambda = 0x7fefffffffffffff;
current_reflected_lambda = 0x7fefffffffffffff;
}
}
//glFlush();
stop = omp_get_wtime();
for (int i = 0; i < (viewport.xvmax - viewport.xvmin); i++)
{
for (int j = 0; j < (viewport.yvmax - viewport.yvmin); j++)
{
glColor3f(tabelaPixlov[i][j].red, tabelaPixlov[i][j].green, tabelaPixlov[i][j].blue);
glBegin(GL_POINTS);
glVertex2i(i, j);
glEnd();
}
}
printf("%f\n št niti:%d\n", stop - start, omp_get_max_threads());
glutSwapBuffers();
}
With ray tracing you should use schedule(dynamic). Besides that I would suggest fusing the loop
#pragma omp parallel for schedule(dynamic) {
for(int n=0; n<((viewport.xvmax - viewport.xvmin)*(viewport.yvmax - viewport.yvmin); n++) {
int i = n/(viewport.yvmax - viewport.yvmin);
int j = n%(viewport.yvmax - viewport.yvmin)
//...
}
Also, why are you setting the number of threads? Just use the default which should be set to the number of logical cores. If you have Hyper Threading ray tracing is one of the algorithms that will benefit from Hyper Threading so you don't want to set the number of threads to the number of physical cores.
In addition to using MIMD with OpenMP I would suggest looking into using SIMD for ray tracing. See Ingo Wald's PhD thesis for an example on how to do this http://www.sci.utah.edu/~wald/PhD/. Basically you shoot four (eight) rays in one SSE (AVX) register and then go down the ray tree for each ray in parallel. However, if one ray finishes you hold it and wait until all four are finished (this is similar to what is done on the GPU). There have been many papers written since which have more advanced tricks based on this idea.

Find local maxima in grayscale image using OpenCV

Does anybody know how to find the local maxima in a grayscale IPL_DEPTH_8U image using OpenCV? HarrisCorner mentions something like that but I'm actually not interested in corners ...
Thanks!
A pixel is considered a local maximum if it is equal to the maximum value in a 'local' neighborhood. The function below captures this property in two lines of code.
To deal with pixels on 'plateaus' (value equal to their neighborhood) one can use the local minimum property, since plateaus pixels are equal to their local minimum. The rest of the code filters out those pixels.
void non_maxima_suppression(const cv::Mat& image, cv::Mat& mask, bool remove_plateaus) {
// find pixels that are equal to the local neighborhood not maximum (including 'plateaus')
cv::dilate(image, mask, cv::Mat());
cv::compare(image, mask, mask, cv::CMP_GE);
// optionally filter out pixels that are equal to the local minimum ('plateaus')
if (remove_plateaus) {
cv::Mat non_plateau_mask;
cv::erode(image, non_plateau_mask, cv::Mat());
cv::compare(image, non_plateau_mask, non_plateau_mask, cv::CMP_GT);
cv::bitwise_and(mask, non_plateau_mask, mask);
}
}
Here's a simple trick. The idea is to dilate with a kernel that contains a hole in the center. After the dilate operation, each pixel is replaced with the maximum of it's neighbors (using a 5 by 5 neighborhood in this example), excluding the original pixel.
Mat1b kernelLM(Size(5, 5), 1u);
kernelLM.at<uchar>(2, 2) = 0u;
Mat imageLM;
dilate(image, imageLM, kernelLM);
Mat1b localMaxima = (image > imageLM);
Actually after I posted the code above I wrote a better and very very faster one ..
The code above suffers even for a 640x480 picture..
I optimized it and now it is very very fast even for 1600x1200 pic.
Here is the code :
void localMaxima(cv::Mat src,cv::Mat &dst,int squareSize)
{
if (squareSize==0)
{
dst = src.clone();
return;
}
Mat m0;
dst = src.clone();
Point maxLoc(0,0);
//1.Be sure to have at least 3x3 for at least looking at 1 pixel close neighbours
// Also the window must be <odd>x<odd>
SANITYCHECK(squareSize,3,1);
int sqrCenter = (squareSize-1)/2;
//2.Create the localWindow mask to get things done faster
// When we find a local maxima we will multiply the subwindow with this MASK
// So that we will not search for those 0 values again and again
Mat localWindowMask = Mat::zeros(Size(squareSize,squareSize),CV_8U);//boolean
localWindowMask.at<unsigned char>(sqrCenter,sqrCenter)=1;
//3.Find the threshold value to threshold the image
//this function here returns the peak of histogram of picture
//the picture is a thresholded picture it will have a lot of zero values in it
//so that the second boolean variable says :
// (boolean) ? "return peak even if it is at 0" : "return peak discarding 0"
int thrshld = maxUsedValInHistogramData(dst,false);
threshold(dst,m0,thrshld,1,THRESH_BINARY);
//4.Now delete all thresholded values from picture
dst = dst.mul(m0);
//put the src in the middle of the big array
for (int row=sqrCenter;row<dst.size().height-sqrCenter;row++)
for (int col=sqrCenter;col<dst.size().width-sqrCenter;col++)
{
//1.if the value is zero it can not be a local maxima
if (dst.at<unsigned char>(row,col)==0)
continue;
//2.the value at (row,col) is not 0 so it can be a local maxima point
m0 = dst.colRange(col-sqrCenter,col+sqrCenter+1).rowRange(row-sqrCenter,row+sqrCenter+1);
minMaxLoc(m0,NULL,NULL,NULL,&maxLoc);
//if the maximum location of this subWindow is at center
//it means we found the local maxima
//so we should delete the surrounding values which lies in the subWindow area
//hence we will not try to find if a point is at localMaxima when already found a neighbour was
if ((maxLoc.x==sqrCenter)&&(maxLoc.y==sqrCenter))
{
m0 = m0.mul(localWindowMask);
//we can skip the values that we already made 0 by the above function
col+=sqrCenter;
}
}
}
The following listing is a function similar to Matlab's "imregionalmax". It looks for at most nLocMax local maxima above threshold, where the found local maxima are at least minDistBtwLocMax pixels apart. It returns the actual number of local maxima found. Notice that it uses OpenCV's minMaxLoc to find global maxima. It is "opencv-self-contained" except for the (easy to implement) function vdist, which computes the (euclidian) distance between points (r,c) and (row,col).
input is one-channel CV_32F matrix, and locations is nLocMax (rows) by 2 (columns) CV_32S matrix.
int imregionalmax(Mat input, int nLocMax, float threshold, float minDistBtwLocMax, Mat locations)
{
Mat scratch = input.clone();
int nFoundLocMax = 0;
for (int i = 0; i < nLocMax; i++) {
Point location;
double maxVal;
minMaxLoc(scratch, NULL, &maxVal, NULL, &location);
if (maxVal > threshold) {
nFoundLocMax += 1;
int row = location.y;
int col = location.x;
locations.at<int>(i,0) = row;
locations.at<int>(i,1) = col;
int r0 = (row-minDistBtwLocMax > -1 ? row-minDistBtwLocMax : 0);
int r1 = (row+minDistBtwLocMax < scratch.rows ? row+minDistBtwLocMax : scratch.rows-1);
int c0 = (col-minDistBtwLocMax > -1 ? col-minDistBtwLocMax : 0);
int c1 = (col+minDistBtwLocMax < scratch.cols ? col+minDistBtwLocMax : scratch.cols-1);
for (int r = r0; r <= r1; r++) {
for (int c = c0; c <= c1; c++) {
if (vdist(Point2DMake(r, c),Point2DMake(row, col)) <= minDistBtwLocMax) {
scratch.at<float>(r,c) = 0.0;
}
}
}
} else {
break;
}
}
return nFoundLocMax;
}
The first question to answer would be what is "local" in your opinion. The answer may well be a square window (say 3x3 or 5x5) or circular window of a certain radius. You can then scan over the entire image with the window centered at each pixel and pick the highest value in the window.
See this for how to access pixel values in OpenCV.
This is very fast method. It stored founded maxima in a vector of
Points.
vector <Point> GetLocalMaxima(const cv::Mat Src,int MatchingSize, int Threshold, int GaussKernel )
{
vector <Point> vMaxLoc(0);
if ((MatchingSize % 2 == 0) || (GaussKernel % 2 == 0)) // MatchingSize and GaussKernel have to be "odd" and > 0
{
return vMaxLoc;
}
vMaxLoc.reserve(100); // Reserve place for fast access
Mat ProcessImg = Src.clone();
int W = Src.cols;
int H = Src.rows;
int SearchWidth = W - MatchingSize;
int SearchHeight = H - MatchingSize;
int MatchingSquareCenter = MatchingSize/2;
if(GaussKernel > 1) // If You need a smoothing
{
GaussianBlur(ProcessImg,ProcessImg,Size(GaussKernel,GaussKernel),0,0,4);
}
uchar* pProcess = (uchar *) ProcessImg.data; // The pointer to image Data
int Shift = MatchingSquareCenter * ( W + 1);
int k = 0;
for(int y=0; y < SearchHeight; ++y)
{
int m = k + Shift;
for(int x=0;x < SearchWidth ; ++x)
{
if (pProcess[m++] >= Threshold)
{
Point LocMax;
Mat mROI(ProcessImg, Rect(x,y,MatchingSize,MatchingSize));
minMaxLoc(mROI,NULL,NULL,NULL,&LocMax);
if (LocMax.x == MatchingSquareCenter && LocMax.y == MatchingSquareCenter)
{
vMaxLoc.push_back(Point( x+LocMax.x,y + LocMax.y ));
// imshow("W1",mROI);cvWaitKey(0); //For gebug
}
}
}
k += W;
}
return vMaxLoc;
}
Found a simple solution.
In this example, if you are trying to find 2 results of a matchTemplate function with a minimum distance from each other.
cv::Mat result;
matchTemplate(search, target, result, CV_TM_SQDIFF_NORMED);
float score1;
cv::Point displacement1 = MinMax(result, score1);
cv::circle(result, cv::Point(displacement1.x+result.cols/2 , displacement1.y+result.rows/2), 10, cv::Scalar(0), CV_FILLED, 8, 0);
float score2;
cv::Point displacement2 = MinMax(result, score2);
where
cv::Point MinMax(cv::Mat &result, float &score)
{
double minVal, maxVal;
cv::Point minLoc, maxLoc, matchLoc;
minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, cv::Mat());
matchLoc.x = minLoc.x - result.cols/2;
matchLoc.y = minLoc.y - result.rows/2;
return minVal;
}
The process is:
Find global Minimum using minMaxLoc
Draw a filled white circle around global minimum using min distance between minima as radius
Find another minimum
The the scores can be compared to each other to determine, for example, the certainty of the match,
To find more than just the global minimum and maximum try using this function from skimage:
http://scikit-image.org/docs/dev/api/skimage.feature.html#skimage.feature.peak_local_max
You can parameterize the minimum distance between peaks, too. And more. To find minima, use negated values (take care of the array type though, 255-image could do the trick).
You can go over each pixel and test if it is a local maxima. Here is how I would do it.
The input is assumed to be type CV_32FC1
#include <vector>//std::vector
#include <algorithm>//std::sort
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/core/core.hpp"
//structure for maximal values including position
struct SRegionalMaxPoint
{
SRegionalMaxPoint():
values(-FLT_MAX),
row(-1),
col(-1)
{}
float values;
int row;
int col;
//ascending order
bool operator()(const SRegionalMaxPoint& a, const SRegionalMaxPoint& b)
{
return a.values < b.values;
}
};
//checks if pixel is local max
bool isRegionalMax(const float* im_ptr, const int& cols )
{
float center = *im_ptr;
bool is_regional_max = true;
im_ptr -= (cols + 1);
for (int ii = 0; ii < 3; ++ii, im_ptr+= (cols-3))
{
for (int jj = 0; jj < 3; ++jj, im_ptr++)
{
if (ii != 1 || jj != 1)
{
is_regional_max &= (center > *im_ptr);
}
}
}
return is_regional_max;
}
void imregionalmax(
const cv::Mat& input,
std::vector<SRegionalMaxPoint>& buffer)
{
//find local max - top maxima
static const int margin = 1;
const int rows = input.rows;
const int cols = input.cols;
for (int i = margin; i < rows - margin; ++i)
{
const float* im_ptr = input.ptr<float>(i, margin);
for (int j = margin; j < cols - margin; ++j, im_ptr++)
{
//Check if pixel is local maximum
if ( isRegionalMax(im_ptr, cols ) )
{
cv::Rect roi = cv::Rect(j - margin, i - margin, 3, 3);
cv::Mat subMat = input(roi);
float val = *im_ptr;
//replace smallest value in buffer
if ( val > buffer[0].values )
{
buffer[0].values = val;
buffer[0].row = i;
buffer[0].col = j;
std::sort(buffer.begin(), buffer.end(), SRegionalMaxPoint());
}
}
}
}
}
For testing the code you can try this:
cv::Mat temp = cv::Mat::zeros(15, 15, CV_32FC1);
temp.at<float>(7, 7) = 1;
temp.at<float>(3, 5) = 6;
temp.at<float>(8, 10) = 4;
temp.at<float>(11, 13) = 7;
temp.at<float>(10, 3) = 8;
temp.at<float>(7, 13) = 3;
vector<SRegionalMaxPoint> buffer_(5);
imregionalmax(temp, buffer_);
cv::Mat debug;
cv::cvtColor(temp, debug, cv::COLOR_GRAY2BGR);
for (auto it = buffer_.begin(); it != buffer_.end(); ++it)
{
circle(debug, cv::Point(it->col, it->row), 1, cv::Scalar(0, 255, 0));
}
This solution does not take plateaus into account so it is not exactly the same as matlab's imregionalmax()
I think you want to use the
MinMaxLoc(arr, mask=NULL)-> (minVal, maxVal, minLoc, maxLoc)
Finds global minimum and maximum in array or subarray
function on you image

Resources