I cannot understand why the following minimal code outputs segmentation fault and cv::Mat values are not printed correctly:
#include <opencv2/opencv.hpp>
int main()
{
unsigned char out[1280*720*3/2] = {100};
cv::Mat dummy_query = cv::Mat(1, 1280*720*3/2*sizeof(unsigned char), CV_8UC1, (void *)out);
cv::Size s = dummy_query.size();
std::cout << s << "\r\n";
for(int i = 0; i < 1280*720*3/2; i++)
{
std::cout << i << "ss" << int(out[i]) << ":";
std::cout << dummy_query.at<int>(0,i) << " ";
}
}
You have defined uchar datatype in cv::Mat but accessing at this line
as int std::cout << dummy_query.at<int>(0,i) << " ";
so your program will likely get crash at end of the loop
e.g.
// create a 100x100 8-bit matrix
Mat M(100,100,CV_8U);
// this will be compiled fine. no any data conversion will be done.
Mat_<float>& M1 = (Mat_<float>&)M;
// the program is likely to crash at the statement below
M1(99,99) = 1.f;
check this open cv reference
Related
In my code I'm encountering a situation where it is running for few hours but crashing at random points after that(SIGSEGV, Segmentation fault). Whenever crash happens, the cv::Mat involved(often different) will have the u parameter as a nullptr. (Link to what u is: https://docs.opencv.org/3.4/d3/d63/classcv_1_1Mat.html#a2742469fe595e1b9036f60d752d08461)
So I'm wondering what this u being a nullptr actually means and if this is the cause for crashing? This is confusing because u is 0x0 or nullptr at other points during execution as well and not just when it crashes.
An example code of how I'm using the mats and causing the u to become 0x0:
#include <opencv2/opencv.hpp>
int main()
{
cv::Mat main_data = cv::Mat::zeros(10, 10, CV_8UC3);
cv::Mat buffer = cv::Mat::zeros(100, 100, CV_8UC3);
cv::Mat valid_data = buffer;
std::cout << "before: " << valid_data.u << std::endl;
memcpy(buffer.data, main_data.data, main_data.rows*main_data.step);
valid_data = cv::Mat(main_data.rows, main_data.cols, main_data.type(), buffer.data, main_data.step[0]);
std::cout << "after: " << valid_data.u << std::endl;
return 0;
}
I have multiple threads and I'm using the above along with locks for sharing data between them.
I defined and initialized a Mat variable using the Mat::zeros, when I print its shape, i.e. rows, cols, channels, it seems I get wrong values.
My code is shown as follows:
#include "opencv2/opencv.hpp"
#include <opencv2/core/core.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char const *argv[])
{
int n_Channel = 3;
int mySizes[3] = {100, 200, n_Channel};
Mat M = Mat::zeros(n_Channel, mySizes, CV_64F);
cout << M.rows << "," << M.cols << "," << M.channels() << endl;
return 0;
}
The printed message is :
-1,-1,1
What's wrong with this?
I also find that if I declare a Mat using the following code:
int n_Channel = 3;
Mat M(Size(100, 200), CV_32FC(n_Channel));
cout << M.rows << "," << M.cols << "," << M.channels() << endl;
the outcome is correct:
200,100,3
I'm confused about this. Thank you all for helping me!
You want to use a very special overloaded version of the cv::Mat::zeros method.
Let's have a look at the following code:
// Number of channels.
const int n_Channel = 3;
// Number of dimensions; must be 1 or 2?
const int n_Dimensions = 2;
// Create empty Mat using zeros, and output dimensions.
int mySizes[n_Dimensions] = { 200, 100 };
cv::Mat M1 = cv::Mat::zeros(n_Dimensions, mySizes, CV_64FC(n_Channel));
std::cout << "M1: " << M1.rows << "," << M1.cols << "," << M1.channels() << std::endl;
// Create empty Mat using constructor, and output dimensions.
cv::Mat M2 = cv::Mat(cv::Size(100, 200), CV_64FC(n_Channel), cv::Scalar(0, 0, 0));
std::cout << "M2: " << M2.rows << "," << M2.cols << "," << M2.channels() << std::endl;
which gives the following output:
M1: 200,100,3
M2: 200,100,3
So, basically you have to move the "channel number info" from mySizes to the cv::Mat::zeros method. Also, you have to pay attention to the order of the image dimensions provided in mySizes, since it seem to differ from the constructor using cv::Size. I guess the latter one is width x height, whereas the first one is number of rows x number of cols.
How to init CV mat :
cv::Mat test = cv::Mat::zeros(cv::Size(100, 200), CV_64F);
As you can see, the first parameter is the Size cf :
https://docs.opencv.org/3.1.0/d3/d63/classcv_1_1Mat.html
What is an optimal way to send OPENCV Mat over MPI? Now I have done it by convetring Mat to int** but this is a bit slow solution.
A = alloc2d(n , m);
for (int i = 0; i < n ; ++i)
for (int j = 0; j < m ; ++j)
A[i][j] = img.at<uchar>(i , j);
/////////////////////////////////////
int ** alloc2d(int rows, int cols) {
int * data = (int *)malloc(rows * cols * sizeof(int));
int ** arr = (int **)malloc(rows * sizeof(int *));
for (int i = 0; i < rows; ++i)
arr[i] = &(data[cols * i]);
return arr;
}
Check the original Mat is contiguous first, and clone it if it isn't.
Then just get the:
rows
columns
type
channels
of the original Mat and save in that order, each as 4 bytes, at the start of a buffer. Then append the appropriate number of bytes from the original Mat's data pointer and send the whole lot.
Do the opposite at the receiving end... read the first four integers from the buffer and create a Mat of the corresponding size and load the remainder of the data into it.
#Miki provides an excellent, related answer here which demonstrates the details of most of the techniques suggested above - look specifically at Mat2str() and str2Mat().
I don't do much C++ or much MPI, I am sure anyone who uses MPI or C++ a lot could tighten it up, but the following works and works pretty fast too!
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <ctime>
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <opencv2/opencv.hpp>
#include "opencv2/highgui/highgui.hpp"
#include "mpi.h"
using namespace std;
using namespace cv;
const int MAXBYTES=8*1024*1024;
uchar buffer[MAXBYTES];
void matsnd(const Mat& m,int dest){
int rows = m.rows;
int cols = m.cols;
int type = m.type();
int channels = m.channels();
memcpy(&buffer[0 * sizeof(int)],(uchar*)&rows,sizeof(int));
memcpy(&buffer[1 * sizeof(int)],(uchar*)&cols,sizeof(int));
memcpy(&buffer[2 * sizeof(int)],(uchar*)&type,sizeof(int));
// See note at end of answer about "bytes" variable below!!!
int bytespersample=1; // change if using shorts or floats
int bytes=m.rows*m.cols*channels*bytespersample;
cout << "matsnd: rows=" << rows << endl;
cout << "matsnd: cols=" << cols << endl;
cout << "matsnd: type=" << type << endl;
cout << "matsnd: channels=" << channels << endl;
cout << "matsnd: bytes=" << bytes << endl;
if(!m.isContinuous())
{
m = m.clone();
}
memcpy(&buffer[3*sizeof(int)],m.data,bytes);
MPI_Send(&buffer,bytes+3*sizeof(int),MPI_UNSIGNED_CHAR,dest,0,MPI_COMM_WORLD);
}
Mat matrcv(int src){
MPI_Status status;
int count,rows,cols,type,channels;
MPI_Recv(&buffer,sizeof(buffer),MPI_UNSIGNED_CHAR,src,0,MPI_COMM_WORLD,&status);
MPI_Get_count(&status,MPI_UNSIGNED_CHAR,&count);
memcpy((uchar*)&rows,&buffer[0 * sizeof(int)], sizeof(int));
memcpy((uchar*)&cols,&buffer[1 * sizeof(int)], sizeof(int));
memcpy((uchar*)&type,&buffer[2 * sizeof(int)], sizeof(int));
cout << "matrcv: Count=" << count << endl;
cout << "matrcv: rows=" << rows << endl;
cout << "matrcv: cols=" << cols << endl;
cout << "matrcv: type=" << type << endl;
// Make the mat
Mat received= Mat(rows,cols,type,(uchar*)&buffer[3*sizeof(int)]);
return received;
}
int main ( int argc, char *argv[] )
{
// Initialise MPI
MPI::Init (argc,argv);
// Get our rank
int id = MPI::COMM_WORLD.Get_rank();
if(id==0)
{
// MASTER - wait to receive image from slave and write to disk for checking
Mat received=matrcv(1);
imwrite("received.jpg",received);
}else{
// Slave - read Mat from disk and send to master
Mat image=imread("image.jpg",IMREAD_COLOR);
matsnd(image,0);
}
// Terminate MPI
MPI::Finalize();
}
I put a loop with 10,000 iterations around:
matsnd() in the slave, and
matrcv() in the Master
and it took 1.9 seconds for the 10,000 iterations. I cannot compare as you didn't show any timings.
All the cout statements that are hard-left justified are just debug stuff that can safely be removed.
Note:
Whilst I have used and tested the above, I have since learned that the calculation of the number of bytes I send may be incorrect in some circumstances (probably where there are alignment constraints). If you are interested, please check this answer.
Keywords: MPI, MPI_Send, MPI_Recv, OpenCV, Mat, image
I am trying to code a program that eliminates some of the connected components and keep the rest.
However, at some point in the code, the program exits with error message "Segmentation fault (core dumped)".
I have narrowed down the error to the statement: "destinationImage.at(row, column) = labeledImage.at(row, column);" using the checkpoints you'll find the code below.
I have tried all the solution I found, especially this one, with no luck.
Please Help!
One more thing, the program reads the image correctly but does not show the original image as per the code. Instead, it prints a message "init done
opengl support available". Is this normal? Does the implementation of the imshow take place at the end of the program with no errors?
/* Goal is to find all related components, eliminate secondary objects*/
#include <opencv2/core/utility.hpp>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
//Declaring variables
Mat originalImage;
int conComponentsCount;
int primaryComponents;
//Declaring constants
const char* keys =
{
"{#image|../data/sample.jpg|image for converting to a grayscale}"
};
//Functions prototypes, used to be able to define functions AFTER the "main" function
Mat BinarizeImage (Mat &, int thresh);
int AverageCCArea(Mat & CCLabelsStats,int numOfLabels, int minCCSize);
bool ComponentIsIncludedCheck (int ccArea, int referenceCCArea);
//Program mainstream============================================
int main (int argc, const char **argv)
{
//Waiting for user to enter the required path, default path is defined in "keys" string
CommandLineParser parser(argc, argv, keys);
string inputImage = parser.get<string>(0);
//Reading original image
//NOTE: the program MUST terminate or loop back if the image was not loaded; functions below use reference to matrices and references CANNOT be null or empty.
originalImage = imread(inputImage.c_str(), IMREAD_GRAYSCALE);// or: imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE)
cout << " 1) Loading image done!" << endl;//CHECKPOINT
if (originalImage.empty())
{
cout << "Nothing was loaded!";
return -1; //terminating program with error feedback
}
cout << " 2) Checking for null Image done!" << endl;//CHECKPOINT
namedWindow("Original Image", 0);
imshow("Original Image", originalImage);
cout << " 3) Showing ORIGINAL image done!" << endl;//CHECKPOINT
//Image Binarization; connectedcomponents function only accepts binary images.
int threshold=100; //Value chosen empirically.
Mat binImg = BinarizeImage(originalImage, threshold);
cout << " 4) Binarizing image done!" << endl;//CHECKPOINT
//Finding the number of connected components and generating the labeled image.
Mat labeledImage; //Image with connected components labeled.
Mat stats, centroids; //Statistics of connected image's components.
conComponentsCount = connectedComponentsWithStats(binImg, labeledImage, stats, centroids, 4, CV_16U);
cout << " 5) Connecting pixels done!" << endl;//CHECKPOINT
//Creating a new matrix to include the final image (without secondary objects)
Mat destinationImage(labeledImage.size(), CV_16U);
//Calculating the average of the labeled image components areas
int ccSizeIncluded = 1000;
int avgComponentArea = AverageCCArea(stats, conComponentsCount, ccSizeIncluded);
cout << " 6) Calculating components avg area done!" << endl;//CHECKPOINT
//Criteria for component sizes
for (int row = 0; row <= labeledImage.rows; row++)
{
cout << " 6a) Starting rows loop iteration # " << row+1 << " done!" << endl;//CHECKPOINT
for (int column = 0; column <= labeledImage.cols; column++)
{
//Criteria for component sizes
int labelValue = labeledImage.at<int>(row, column);
if (ComponentIsIncludedCheck (stats.at<int>(labelValue, CC_STAT_AREA), avgComponentArea))
{
//Setting pixel value to the "destinationImage"
destinationImage.at<int>(row, column) = labeledImage.at<int>(row, column);
cout << " 6b) Setting pixel (" << row << "," << column << ") done!" << endl;//CHECKPOINT
}
else
cout << " 6c) Pixel (" << row << "," << column << ") Skipped!" << endl;//CHECKPOINT
}
cout << " 6d) Row " << row << " done!" << endl;//CHECKPOINT
}
cout << " 7) Showing FINAL image done!" << endl;//CHECKPOINT
namedWindow("Final Image", 0);
imshow("Final Image", destinationImage);
cout << " 8) Program done!" << endl;//CHECKPOINT
waitKey (0);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++
Mat BinarizeImage (Mat & originalImg, int threshold=100) //default value of threshold of grey content.
{
// Binarization of image to be used in connectedcomponents function.
Mat bw = threshold < 128 ? (originalImg < threshold) : (originalImg > threshold);
return bw;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++
int AverageCCArea(Mat & CCLabelsStats,int numOfLabels, int minCCSize) //calculates the average area of connected components without components smaller than minCCSize pixels..... reference is used to improve performance, passing-by-reference does not require copying the matrix to this function.
{
int average;
for (int i=1; i<=numOfLabels; i++)
{
int sum = 0;
int validComponentsCount = numOfLabels - 1;
if (CCLabelsStats.at<int>(i, CC_STAT_AREA) >= minCCSize)
{
sum += CCLabelsStats.at<int>(i, CC_STAT_AREA);
}
else
{
validComponentsCount--;
}
average = sum / (validComponentsCount);
}
return average;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++
bool ComponentIsIncludedCheck (int ccArea, int referenceCCArea)
{
if (ccArea >= referenceCCArea)
{
return true; //Component should be included in the destination image
}
else
{
return false; //Component should NOT be included in the destination image
}
}
change this:
for (int row = 0; row <= labeledImage.rows; row++)
to this:
for (int row = 0; row < labeledImage.rows; row++)
and this:
for (int column = 0; column <= labeledImage.cols; column++)
to this:
for (int column = 0; column < labeledImage.cols; column++)
any good?
(remember that in C++ we start counting from 0, so if e.g. labeledImage.cols == 10, the last column is the one with the index 9)
int main () {
Mat A = Mat::ones(100, 100, CV_8U)*3;
cout << A.at<int>(0,0) << endl;
return 0;
}
The output is a a very large number :: 50529027
Can anyone help me out?? C++ code
you're casting to the wrong type in A.at<int>() // should be uchar instead of int
so, A.at<int>(0,0) sees 0x03030303, which is, in fact 50529027.
Mat A = Mat::ones(100, 100, CV_8U)*3;
cout << int(A.at<uchar>(0,0)) << endl;
(the cast around A.at() is just to show a number with cout instead of a char )