I read some opencv codes on using template Mat_ matrix. Here they are:
Mat image = Mat:zeros(512,512,CV_8UC3);
for (int i = 0; i < image.rows; ++i)
for (int j = 0; j < image.cols; ++j)
{
Mat sampleMat = (Mat_<float>(1,2) << j,i);
.....
}
The sampleMat is Mat sampleMat(1,2,CV_32FC1). Whey need using (Mat_<float>(1,2) << j,i)?
Related
I'm using opencv dnn for infering onnx model, and I'v found dnn::blobFromImage can transfer an image to blob as input of dnn::Net, but if there anyway to transfer arbitary shape tensor (e.g. (1,8,256,256) instead of 3 channels) to blob for infering ?
Seems no function specially.
Just construct this Mat:
int arr[4] = {64, 8, 21, 3};
Mat kp(4, arr, CV_32FC1, Scalar::all(0));
cout << r.size() << endl;
for (int b = 0; b < r.size(); b++)
{
for (int c = 0; c < r[b].size(); c++)
{
for (int h = 0; h < r[b][c].size(); h++)
{
for (int w = 0; w < r[b][c][h].size(); w++)
{
kp.ptr<float>(b, c, h)[w] = r[b][c][h][w].asFloat();
}
}
}
}
How to efficiency linearized Mat (symmetric matrix) to one row by right triangle.
For example, when I have:
0aabbb
b0aaaa
ba0bba
bac0aa
aaaa0c
abcab0
and then from that I get:
aabbbaaaabbaaac
Something like this:
...
template<class T>
Mat SSMJ::triangleLinearized(Mat mat){
int c = mat.cols;
Mat row = Mat(1, ((c*c)-c)/2, mat.type());
int i = 0;
for(int y = 1; y < mat.rows; y++)
for(int x = y; x < mat.cols; x++) {
row.at<T>(i)=mat.at<T>(y, x);
i++;
}
return row;
}
...
Since data in your mat is just a 1d array stored in row.data you can do whatever you want with it. I don't think you will find anything more special (w/o using vectorized methods) than just copying from this array.
int rows = 6;
char data[] = { 0,1,2,3,4,5,
0,1,2,3,4,5,
0,1,2,3,4,5,
0,1,2,3,4,5,
0,1,2,3,4,5};
char result[100];
int offset = 0;
for (int i = 0; i < 5; offset += 5-i, i++) {
memcpy(&result[offset] , &data[rows * i + i + 1], 5 - i);
}
Or with opencv Mat it would be
int rows = mat.cols;
char result[100]; // you can calculate how much data u need
int offset = 0;
for (int i = 0; i < 5; offset += 5-i, i++) {
memcpy(&result[offset] , &mat.data[rows * i + i + 1], 5 - i);
}
Mat resultMat(1, offset, result);
How can I convert byte array to Mat which is received from socket ?.
My client application will send color image data like this
Mat frame; //colour image
int imgSize = frame.total()*frame.elemSize();
int bytes = send(clientSock, frame.data, imgSize, 0));//write to the socket
And the server will receives the data like
char sockData[imgSize];
Mat img;
for (int i = 0; i < imgSize; i += bytes) {
bytes = recv(connectSock, sockData +i, imgSize - i, 0));
}
// Write to mat
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
(img.row(i)).col(j) = (uchar)sockData[((img.cols)*i)+j];
}
}
I am getting distorted image at the receiver. Is there any problem in my code ?
Thanks in advance.......
If you have colour image you may read it in a math with 3 channels of uchar so change this piece of code:
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
(img.row(i)).col(j) = (uchar)sockData[((img.cols)*i)+j];
}
}
with this:
int baseIndex = 0;
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
img.at<cv::Vec3b>(i,j) = cv::Vec3b(sockData[baseIndex + 0],
sockData[baseIndex + 1],
sockData[baseIndex + 2]);
baseIndex = baseIndex + 3;
}
}
Maybe this should work.
Doesn't this work?
cv::Mat frame(img.rows, img.cols, CV_8UC3, sockData);
Just replace CV_8UC3 with the correct image format:
CV_<bit-depth>{U|S|F}C(<number_of_channels>)
see https://docs.opencv.org/2.4/modules/core/doc/basic_structures.html
Edit: There is a 5th additional field which can be useful. The number of bytes per row (in case there are a few padding bytes). In working with V4L2 today, I successfully used this cv::Mat constructor:
v4l2_format camera_format = ...; // see https://linuxtv.org/downloads/v4l-dvb-apis/uapi/v4l/vidioc-g-fmt.html#description
cv::Mat mat(camera_format.fmt.pix.height,
camera_format.fmt.pix.width,
CV_8UC3,
raw_data_ptr,
camera_format.fmt.pix.bytesperline);
I solved the problem using below code.
int ptr=0;
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
img.at<cv::Vec3b>(i,j) = cv::Vec3b(sockData[ptr+0],sockData[ptr+1],sockData[ptr+2]);
ptr=ptr+3;
}
}
Adding to Michele answer, one can also use the MatIterator to solve this.
cv::Mat m;
m.create(10, 10, CV_32FC3);
// This is the socket data.
float *array = (float *)malloc( 3*sizeof(float)*10*10 );
cv::MatIterator_<cv::Vec3f> it = m.begin<cv::Vec3f>();
for (unsigned i = 0; it != m.end<cv::Vec3f>(); it++ ) {
for ( unsigned j = 0; j < 3; j++ ) {
(*it)[j] = *(array + i );
i++;
}
}
Now you have a float cv::Mat. In case of 8 bit, simply change float to uchar and Vec3f to Vec3b and CV_32FC3 to CV_8UC3
I need to convert the code below from C++ to Java. In C++ I use openCV and I need to convert it in Java using JavaCV.
IplImage* img = cvLoadImage(argv[0]);
int rows = img->height;
int cols = img->width;
Mat matimg(img);
vector<vector<double> > img_vec(rows, vector<double>(cols));
for (int i=0; i < rows; i++) {
for (int j =0; j < cols; j++){
unsigned char temp;
temp = ((uchar*) matimg.data + i * matimg.step)[j * matimg.elemSize() + 1 ];
img_vec[i][j] = (double) temp;
}
}
I've tried the following conversion to java, but it doesn't work properly. I printed the values of temp and it is 0 all the times and for the same imgage the values of matimg.step and matimg.elemSize() are different in the C++ code and the Java code.
In c++ I get matimg.step = 2400 and matimg.elemSize() = 3 while in Java i get 3000 and 1.
Here is the code in java:
IplImage img = cvLoadImage(argv[0]);
int rows = img.height();
int cols = img.width();
CvMat matimg = img.asCvMat();
double img_vec[][] = new double[rows][cols];
for (int i=0; i < rows; i++) {
for (int j =0; j < cols; j++){
short temp;
temp = matimg.data_s().get(i * matimg.step() + j * matimg.elemSize() + 1);
img_vec[i][j] = (double) temp;
}
}
I don't understand where am I doing wrong?
Any help is appreciated,
Thanks.
I've solved my problem using this:
ByteBuffer buffer = img.getByteBuffer();
double img_vec[][] = new double[rows][cols];
for (int i=0; i < rows; i++) {
for (int j =0; j < cols; j++){
int ind = i * img.widthStep() + j * img.nChannels() + 1;
img_vec[i][j] = (buffer.get(ind) & 0xFF);
}
}
I currently want to read in some values into a 3-channel, 480 row by 640 column matrix of 8 bit unsigned integer values. I am initializing the matrix like this:
Declaration:
rgbMatrix = Mat::zeros(480,640,CV_8UC3);
When I try to iterate through the entire matrix I am unable to assign/grab values using the following method. The values simply stay 0. My code looks like this:
for (int i = 0; i < rgbMatrix.rows; i++)
{
for (int j = 0; j < rgbMatrix.cols; j++)
{
(rgbMatrix.data + rgbMatrix.step * i)[j * rgbMatrix.channels() + 0] = *value0*;
(rgbMatrix.data + rgbMatrix.step * i)[j * rgbMatrix.channels() + 1] = *value1*;
(rgbMatrix.data + rgbMatrix.step * i)[j * rgbMatrix.channels() + 2] = *value2*;
}
}
However, when I declare three separate 1-channel matrices (also 480 row by 640 column of 8 bit unsigned integer values) and attempt to access elements of those matrices the following code works:
Declaration:
rgbMatrix0 = Mat::zeros(480,640,CV_8UC1);
rgbMatrix1 = Mat::zeros(480,640,CV_8UC1);
rgbMatrix2 = Mat::zeros(480,640,CV_8UC1);
for (int i = 0; i < rgbMatrix0.rows; i++)
{
for (int j = 0; j < rgbMatrix0.cols; j++)
{
(rgbMatrix0.data + rgbMatrix0.step * i)[j] = *value0*;
(rgbMatrix1.data + rgbMatrix1.step * i)[j] = *value1*;
(rgbMatrix2.data + rgbMatrix2.step * i)[j] = *value2*;
}
}
Now, I want to use just one matrix for these operations, as having to keep track of three separate variables will get tiresome after a while. I have a feeling that I am not accessing the right point in memory for the three-channel matrix. Does anyone know how I can accomplish what I did in the second portion of code but using one three-channel matrix instead of three separate one-channel matrices?
Thanks.
There are plenty of ways to do it, for example:
cv::Mat rgbMatrix(480,640,CV_8UC3);
for (int i = 0; i < rgbMatrix.rows; i++)
for (int j = 0; j < rgbMatrix.cols; j++)
for (int k = 0; k < 3; k++)
rgbMatrix.at<cv::Vec3b>(i,j)[k] = value;
[k] here is the channel value.
To set the all the matrix elements to a specific value like 5 for example you can do this:
cv::Mat rgbMatrix2(cv::Size(480,640), CV_8UC3, cv::Scalar(5,5,5));
std::cout << rgbMatrix2 << std::endl;
Sorry I can't see your code since I am writing from iPhone. When you use 3 channel matrix you can get the pixel using:
Vec3b pix = rgbMatrix.at(row,col);
Now you can access channel using:
pix[0] = 255; pix[1] += pix[2];
P.s. Generally rgbMatrix pixel is of type vec3b or vec3d. Always cast image.at<> with relevant type
Very Simple using Vec3b - for uchar, Vec3i - for int, Vec3f - for float, Vec3d - for double
Mat rgbMatrix = Mat::zeros(480,640,CV_8UC1);
for (int i = 0; i < rgbMatrix.rows; i++)
{
for (int j = 0; j < rgbMatrix.cols; j++)
{
rgbMatrix.at<Vec3b>(i,j)[0] = *value0;
rgbMatrix.at<Vec3b>(i,j)[1] = *value1;
rgbMatrix.at<Vec3b>(i,j)[2] = *value2;
}
}
vector<cv::Point3f> xyzBuffer;
cv::Mat xyzBuffMat = cv::Mat(307200, 1, CV_32FC3);
for (int i = 0; i < xyzBuffer.size(); i++) {
xyzBuffMat.at<cv::Vec3f>(i, 1, 0) = xyzBuffer[i].x;
xyzBuffMat.at<cv::Vec3f>(i, 1, 1) = xyzBuffer[i].y;
xyzBuffMat.at<cv::Vec3f>(i, 1, 2) = xyzBuffer[i].z;
}
Here, 0, 1, and 2 are respectively the channels that store x, y and z values.