getting the mean value of image parts - c++

I'm trying to subdivide a gray frame in multiple small squares and than caluculate for each one of them the mean color value of each one so I can build a result frame that display those values, here 's what I' done :
int main (){
cv::Mat frame= cv::imread("test2.jpg",0), result, myROI;
int key = 0;
int roiSize =10;
cv::Scalar mean(0);
cv::Mat meanS;
meanS = cv::Mat::zeros (frame.rows/roiSize,frame.cols/roiSize,CV_32FC1) ;
cv::Rect roi;
if(frame.channels()!=1)
cv::cvtColor(frame,frame,CV_BGR2GRAY);
for ( int i=0 ; i< frame.cols /roiSize; i++){
for (int j = 0 ; j < frame.rows/roiSize; j++){
roi.x= i*roiSize;
roi.y= j*roiSize;
roi.height=roiSize;
roi.width= roiSize;
myROI = frame(roi);
cv::imshow("myRoi",myROI);
mean = cv::mean(myROI);
std::cout << mean[0] << std::endl;
meanS.at<float>(j,i) = mean[0];
}
}
//meanS *=1/255; // I've tried this one also, it didn't help !
cv::imshow("the reuslt ",meanS);
cv::waitKey(0);
return 0;
}
in the console the values are correct but when I display the result with imshow I get only a white frame ! !!
any Idea how can I solve this ?
thanks in advance !

your comment line is actually correct but it's doing integer division and thus multiplying by zero. just add a dot at the end like meanS *=1/255.; // I've tried this one also, it didn't help !

Related

Mat cells set to NULL in OpenCV?

Quick summary:
I create a cv::Mat by
cv::Mat m = cv::Mat::zeros(MAP_HEIGHT, MAP_WIDTH, CV_8UC1)
My approach after this is to see if i have any polygons in a list of polygons, and if i do, fill them in, and lastly i assign m to my public cv::Mat map (defined in the header-file).
What happens is basically:
cv::Mat m = cv::Mat::zeros(MAP_HEIGHT, MAP_WIDTH, CV_8UC1);
// possibly fill polygons with 1's. Nothing happens if there are no polygons
map = m;
The logic of my program is that position x,y is allowed if a 0 is occupying the cell. So no polygons => all map should be 'legit'.
I have defined this method to check whether a given x-y coordinate is allowed.
bool Map::isAllowed(bool res, int x, int y) {
unsigned char allowed = 0;
res = (map.ptr<unsigned char>(y)[x] == allowed);
}
Now the mystery begins.
cout << cv::countNonZero(map) << endl; // prints 0, meaning all cells are 0
for(int i = 0; i < MAP_HEIGHT; i++) {
unsigned char* c = map.ptr<unsigned char>(i);
for(int j = 0; j < MAP_WIDTH; j++) {
cout << c[j] << endl;
}
} // will print nothing, only outputs empty lines, followed by a newline.
If i print (c[j] == NULL) it prints 1.
If i print the entire Mat i see only 0's flashing over my screen, so they are clearly there.
Why does isAllowed(bool, x, y) return false for (0,0), when there is clearly a 0 there?
Let me know if any more information is needed, thanks!
Problem is solved now, here are my mistakes for future reference:
1: When printing, #Miki pointed out that unsigned characters -> ASCII value gets printed, not numerical representation.
2: in isAllowedPosition(bool res, int x, int y), res has a primitive type. Aka this is pushed on the stack and not a reference to a memorylocation. When writing to it, i write to the local copy and not to the one passed in as an argumet.
Two possible fixes, either pass in a pointer to a memorylocation and write to that, or simply return the result.
Since your data type is uchar (aka unsigned char), you're printing the ASCII value. Use
cout << int(c[j]) << endl;
to print the actual value.
Also map.ptr<unsigned char>(y)[x] can be rewritten simply as map.at<uchar>(y,x), or if you use Mat1b as map(y,x)

How does the return value "res" is updated? (ConcativeMat Con NN)

I have a questions about a for loop and its return value. This is C++ code, and I'm using openCV 2.4V.
Input to this function is max value of 600 images with pooling.
600 images << pooling << max value points.
The size of "res" matrix is 600x128 and vec.size() = 600.
For me, within the for loop, the res never get updated, however return value is not zeros.
I suspected
"ptmat.copyTo(subView)"
because, I thought that is not necessary line. However when I took that out, res did not get updated(being zero like initial Mat). Can anybody explain how does the res value get updated?
Also why does this function is called concatenate..?
Mat
concatenateMat(vector<vector<Mat> > &vec) {
int subFeatures = vec[0][0].rows * vec[0][0].cols;
int height = vec[0].size() * subFeatures;
int width = vec.size();
Mat res = Mat::zeros(height, width, CV_64FC1);
for (int i = 0; i<vec.size(); i++) {
for (int j = 0; j<vec[i].size(); j++) {
Rect roi = Rect(i, j * subFeatures, 1, subFeatures);
Mat subView = res(roi);
Mat ptmat = vec[i][j].reshape(0, subFeatures);
ptmat.copyTo(subView);
}
}
return res;
}
According to OpenCV documentation, the Mat::operator() does not make a copy of matrix data, thus any change to subView matrix object in the loop will be reflected in res matrix object as well. That's the line you've mentioned:
ptmat.copyTo(subView);
It's called concatenate because it concatenates 2D vector of Mat objects into a single one.

Problems writing to a subsection of a Mat-Object

I'm new to OpenCV a have some trouble regarding writing to a subrange of a Mat-Object.
The code below iterates a given Image. For each pixel, it takes pixel within a range of 5x5, finds the brightest pixel, and put all other pixel to 0.
I call the function multiple times. After a random number of calls the function gives me a segmentation fault or "malloc memory corruption". Sometimes I can call the function 10 times with no problems sometimes only twice, then the program stops.
I tracked down the problem to the line, where I write to the original image using the subimage.
subimage.at<uchar>(rowSubimage,colSubimage) = 0;
There is the function that drives me crazy:
void findMaxAndBlackout(Mat& image, int size){
Point centralPoint;
Size rangeSize = Size(size,size);
Mat subimage;
Rect range;
// iterate the image
for(int row = 0; row <= image.rows-size; row++){
for(int col = 0; col <= image.cols-size; col++){
centralPoint = Point(col,row);
range = Rect(centralPoint, rangeSize);
// slice submatrix and find max
subimage = image(range);
double max;
minMaxLoc( subimage, NULL, &max, NULL, NULL );
// iterate the surrounding
for(int rowSubimage = 0; rowSubimage <= subimage.rows; rowSubimage++){
for(int colSubimage = 0; colSubimage <= subimage.cols; colSubimage++){
if(subimage.at<uchar>(rowSubimage,colSubimage) < max){
//this line cause the trouble
subimage.at<uchar>(rowSubimage,colSubimage) = 0;
}
}
}
}
}}
The Mat-Object is generated using:
Mat houghImage = imread("small_schachbrett1_cam.png", CV_LOAD_IMAGE_GRAYSCALE);
Please help me understand the problem.
If you know a better or more efficient way to achieve the same result please let me know. I am open for any improvements
Regards
benniz
You are out of range:
row <= image.rows-size
col <= image.cols-size
rowSubimage <= subimage.rows
colSubimage <= subimage.cols
should be
row < image.rows-size
col < image.cols-size
rowSubimage < subimage.rows
colSubimage < subimage.cols

Finding Local Maxima Grayscale Image opencv

I am trying to create my personal Blob Detection algorithm
As far as I know I first must create different Gaussian Kernels with different sigmas (which I am doing using Mat kernel= getGaussianKernel(x,y);) Then get the Laplacian of that kernel and then filter the Image with that so I create my scalespace. Now I need to find the Local Maximas in each result Image of the scalespace. But I cannot seem to find a proper way to do so.... my Code so far is
vector <Point> GetLocalMaxima(const cv::Mat Src,int MatchingSize, int Threshold)
{
vector <Point> vMaxLoc(0);
if ((MatchingSize % 2 == 0) ) // MatchingSize has 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;
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;
}
which I found in this thread here, which it supposedly returns a vector of points where the maximas are. it does return a vector of points but all the x and y coordinates of each point are always -17891602... What to do???
Please if you are to lead me in something else other than correcting my code be informative because I know nothing about opencv. I am just learning
The problem here is that your LocMax point is declared inside the inner loop and never initialized, so it's returning garbage data every time. If you look back at the StackOverflow question you linked, you'll see that their similar variable Point maxLoc(0,0) is declared at the top and constructed to point at the middle of the search window. It only needs to be initialized once. Subsequent loop iterations will replace the value with the minMaxLoc function result.
In summary, remove this line in your inner loop:
Point LocMax; // delete this
And add a slightly altered version near the top:
vector <Point> vMaxLoc(0); // This was your original first line
Point LocMax(0,0); // your new second line
That should get you started anyway.
I found it guys. The problem was my threshold was too high. I do not understand why it gave me negative points instead of zero points but lowering the threshold worked

OpenCV: Partitioning a cv::Mat

I'm trying to partition a cv::Mat into smaller cv::Mat's using OpenCV. I found this method online but I can't get it to work. I want to partition a cv::Mat of, say 640 x 480 into blocks of say, 32 x 32 and operate on each block individually as I go along.
Here is my code. curr_frame contains the total image as a cv::Mat. N_per_col and N_per_row contain the number of mb_sz x mb_sz blocks per column and row respectively.
void ClassName::partition( void )
{
for( i = 0; i < N_per_col; i += mb_sz )
{
for( j = 0; j < N_per_row; j += mb_sz )
{
cv::Mat tmp_img( curr_frame, cv::Rect( i, j, mb_sz, mb_sz ) );
// Do stuff with tmp_img here
}
}
}
This compiles fine but at runtime I get an image full of NULL pixels in tmp_img. curr_frame is definitely OK, as I can view it with imshow().
The documentation is not very clear on this, so any help would be greatly appreciated.
As i mentioned in the comments, the code is corret. to be sure, I tested it with opencv 2.4.1 and the result was as you would expect. so i guess the problem is with something else not mentioned here.