Opencv Mat efficiency linearized by right triangle - opencv

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);

Related

Implementation of LASSO in C

I am trying to understand the LASSO algorithm for linear regression. I have implemented the algorithm using naive coordinate descent method for optimization. However the coefficients that I obtained from my code, wasn't matching with those obtained from the 'glmnet'package for LASSO in R. I wanted to understand how I could make the algorithm more accurate, so that the coefficients match with those obtained from R. I think they use coordinate descent as well.
Note: I have generated some toy data with 11 observations, and 6
features(x,x^2 ,x^3,...,x^6). The last column contains the y values
generated from a dummy function (e^(-x^2)). I wanted to use LASSO to
estimate this function. Also, I have randomly picked the initial
weight vector, multiple times to crosscheck my results.
Here is my code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<time.h>
int num_dim = 6;
int num_obs = 11;
/*Computes the normalization factor*/
float norm_feature(int j,double arr[][7],int n){
float sum = 0.0;
int i;
for(i=0;i<n;i++){
sum = sum + pow(arr[i][j],2);
}
return sum;
}
/*Computes the partial sum*/
float approx(int dim,int d_ignore,float weights[],double arr[][7],int
i){
int flag = 1;
if(d_ignore == -1)
flag = 0;
int j;
float sum = 0.0;
for(j=0;j<dim;j++){
if(j != d_ignore)
sum = sum + weights[j]*arr[i][j];
else
continue;
}
return sum;
}
/* Computes rho-j */
float rho_j(double arr[][7],int n,int j,float weights[7]){
float sum = 0.0;
int i;
float partial_sum ;
for(i=0;i<n;i++){
partial_sum = approx(num_dim,j,weights,arr,i);
sum = sum + arr[i][j]*(arr[i][num_dim]-partial_sum);
}
return sum;
}
float intercept(float arr1[7],double arr[][7],int dim) {
int i;
float sum =0.0;
for (i = 0; i < num_obs; i++) {
sum = sum + pow((arr[i][num_dim]) - approx(num_dim, -1, arr1, arr,
i), 1);
}
return sum;
}
int main(){
double data[num_obs][7];
int i=0,j=0;
float a = 1.0;
float lambda = 0.1; //Setting lambda
float weights[7]; //weights[6] contains the intercept
srand((unsigned int) time(NULL));
/*Generating the data matrix */
for(i=0;i<11;i++)
data[i][0] = ((float)rand()/(float)(RAND_MAX)) * a;
for(i=0;i<11;i++)
for(j=1;j<6;j++)
data[i][j] = pow(data[i][0],j+1);
for(i=0;i<11;i++)
data[i][6] = exp(-pow(data[i][0],2)); // the last column in the
datamatrix contains the y values generated by the dummy function
/*Printing the data matrix */
printf("Data Matrix:\n");
for(i=0;i<11;i++){
for(j=0;j<7;j++){
printf("%lf ",data[i][j]);}
printf("\n");}
printf("\n");
int seed =0;
while(seed<20) {
//Initializing the weight vector
for (i = 0; i < 7; i++)
weights[i] = ((float) rand() / (float) (RAND_MAX)) * a;
int iter = 500;
int t = 0;
int r, l;
double rho[num_dim];
for (i = 0; i < 6; i++) {
rho[i] = rho_j(data, num_obs, r, weights);
}
// Intercept initialization
weights[num_dim] = intercept(weights,data,num_dim);
printf("Weights initialization: ");
for (i = 0; i < (num_dim+1); i++)
printf("%f ", weights[i]);
printf("\n");
while (t < iter) {
for (r = 0; r < num_dim; r++) {
rho[r] = rho_j(data, num_obs, r, weights);
//printf("rho %d:%f ",r,rho[r]);
if (rho[r] < -lambda / 2)
weights[r] = (rho[r] + lambda / 2) / norm_feature(r,
data, num_obs);
else if (rho[r] > lambda / 2)
weights[r] = (rho[r] - lambda / 2) / norm_feature(r,
data, num_obs);
else
weights[r] = 0;
weights[num_dim] = intercept(weights, data, num_dim);
}
/* printf("Iter(%d): ", t);
for (l = 0; l < 7; l++)
printf("%f ", weights[l]);
printf("\n");*/
t++;
}
//printf("\n");
printf("Final Weights: ");
for (i = 0; i < 7; i++)
printf("%f ", weights[i]);
printf("\n");
printf("\n");
seed++;
}
return 0;
}
PseudoCode:

resize matrix with copying the data opencv

I am trying to create a matrix with only one column from another matrix and of course with copying the data.
void redim( Mat in , Mat &out) {
for (int l=0 ; l < in.rows*in.cols ; l++){
for(int j=0; j< in.rows ; j++){
for(int i=0 ; i < in.cols; i++){
out.at <float> (l,0)= in.at <float> (j,i);
}
}
}
}
int main(){
Mat It3;
It3 = (Mat_<double>(2,3) << 0,4,6,7,8,9);
Mat S= Mat :: zeros ( It3.rows* It3.cols , 1, CV_32FC1) ;
redim(It3,S);
waitKey();
}
But I got as result the matrix S=[0;0;0;0;0;0].
Your are mixing float and double as data type. Choose one!
Your for loops don't make any sense.
You can:
correct your for loop, as in toSingleColumn1
using a for loop, but using indices, as in toSingleColumn2
using cv::reshape, which does exactly this, as in toSingleColumn3
See the code below. b1, b2 and b3 will be equal:
#include <opencv2\opencv.hpp>
using namespace cv;
// Use two for loops, with coordinates
void toSingleColumn1(const Mat1f& src, Mat1f& dst)
{
int N = src.rows * src.cols;
dst = Mat1f(N, 1);
int i=0;
for (int r = 0; r < src.rows; ++r) {
for (int c = 0; c < src.cols; ++c) {
dst(i++, 0) = src(r, c);
}
}
}
// Use a single for loop, with indices
void toSingleColumn2(const Mat1f& src, Mat1f& dst)
{
int N = src.rows * src.cols;
dst = Mat1f(N, 1);
for (int i = 0; i < N; ++i) {
dst(i) = src(i);
}
}
// Use cv::reshape
void toSingleColumn3(const Mat& src, Mat& dst)
{
// The 'clone()' is needed to deep copy the data
dst = src.reshape(src.channels(), src.rows*src.cols).clone();
}
int main()
{
Mat1f a = (Mat1f(2,3) << 0.f, 4.f, 6.f, 7.f, 8.f, 9.f);
Mat1f b1, b2, b3;
toSingleColumn1(a, b1);
toSingleColumn2(a, b2);
toSingleColumn3(a, b3);
return 0;
}

OpenCV C++ Convert Byte array to Mat

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

Obtain array from IplImage in JavaCV

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);
}
}

OpenCV Mat class: Accessing elements of a multi-channel matrix

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.

Resources