Converting Caffe caffe::Datum to OpenCV cv::Mat in C++ - c++

I'm doing some debugging and so I'm dumping image files to look at the predictions and transformations.
I can create a caffe::Datum from cv::Mat:
cv::Mat matrix;
// ... initialize matrix
caffe::Datum datum;
caffe::CVMatToDatum(matrix, &datum)
but how do I create a cv::Mat from caffe::Datum? The following code gives the fatal exception "Datum not encoded":
caffe::Datum datum;
// ... initialize datum
cv::Mat matrix;
matrix = DecodeDatumToCVMat(datum, true);

You can use following functions.
cv::Mat DatumToCVMat(const Datum& datum){
int datum_channels = datum.channels();
int datum_height = datum.height();
int datum_width = datum.width();
string strData = datum.data();
cv::Mat cv_img;
if (strData.size() != 0)
{
cv_img.create(datum_height, datum_width, CV_8UC(datum_channels));
const string& data = datum.data();
std::vector<char> vec_data(data.c_str(), data.c_str() + data.size());
for (int h = 0; h < datum_height; ++h) {
uchar* ptr = cv_img.ptr<uchar>(h);
int img_index = 0;
for (int w = 0; w < datum_width; ++w) {
for (int c = 0; c < datum_channels; ++c) {
int datum_index = (c * datum_height + h) * datum_width + w;
ptr[img_index++] = static_cast<uchar>(vec_data[datum_index]);
}
}
}
}
else
{
cv_img.create(datum_height, datum_width, CV_32FC(datum_channels));
for (int h = 0; h < datum_height; ++h) {
float* ptr = cv_img.ptr<float>(h);
int img_index = 0;
for (int w = 0; w < datum_width; ++w) {
for (int c = 0; c < datum_channels; ++c) {
ptr[img_index++] = static_cast<float>(datum.float_data(img_index));
}
}
}
}
return cv_img;
}
all code :
http://lab.deepaivision.com/2017/06/opencv-mat-caffe-datum-datum-mat.html

Addition to the answer by #ttagu99 , in the float section there is a slight bug:
The line:
ptr[img_index++] = static_cast<float>(datum.float_data(img_index));
Should be in fact:
int datum_index = (c * datum_height + h) * datum_width + w;
ptr[img_index++] = static_cast<float>(datum->float_data(datum_index));
This fixes the order of writing the data to the matrix. Otherwise, you only see lines of color.

Related

stack overflow error but cant allocate on the heap

I am trying to multithread a raytracer, and am trying to write a function to pass into the thread. The function throws a stack overflow error, and when I try to heap allocate, all of a sudden I can't write to the array. Any tips?
std::array<std::array<std::array<int,3>,400>,225> idk(std::array<std::array<std::array<int,3>,400>,225> pc,const int img_start,const camera &cam,const hittableList &world,const int imageWidth,const int img_end,const int maxDepth,const int samplesPerPixel,bool fml){
auto pic = std::array<std::array<std::array<int,3>,400>,225> {};
for (int i = img_start; i >= img_end; --i) {
color pixelColour(0, 0, 0);
for (int j = 0; j < 400; j++) {
for (int k = 0; k < samplesPerPixel; k++) {
double u = double(j + randomDouble()) / (imageWidth - 1);
double v = double(i + randomDouble()) / (img_start - 1);
ray r = cam.get_ray(u, v);
pixelColour += rayColor(r, world, maxDepth);
}
pic[i][j] = writeColour(pixelColour, maxDepth);
}
}
fml = true;
return pic;
}
std::array<std::array<std::array<int,3>,400>,225>* idk(std::array<std::array<std::array<int,3>,400>,225> pc,const int img_start,const camera &cam,const hittableList &world,const int imageWidth,const int img_end,const int maxDepth,const int samplesPerPixel,bool fml){
auto* pic = new std::array<std::array<std::array<int,3>,400>,225> {};
for (int i = img_start; i >= img_end; --i) {
color pixelColour(0, 0, 0);
for (int j = 0; j < 400; j++) {
for (int k = 0; k < samplesPerPixel; k++) {
double u = double(j + randomDouble()) / (imageWidth - 1);
double v = double(i + randomDouble()) / (img_start - 1);
ray r = cam.get_ray(u, v);
pixelColour += rayColor(r, world, maxDepth);
}
//this line doesnt work the = is underlined and says: no viable overloas '='
pic[i][j] = writeColour(pixelColour, maxDepth);
}
}
fml = true;
return pic;
}
The C++ standard library requires that the payload of std::array has the same storage duration as the std::array itself.
In other words, you are attempting to place 400 * 255 * 3 ints on your stack, and that is above a run-time limit.
A fix is to use a multidimensional array from a third party library like Boost.MultiArray (part of www.boost.org).

Error in OpenCV Edgeboxes sample program

I have tried the new OpenCV edge boxes implementation. I ran the edgeboxes_demo program from OpenCV ximgproc samples and it causes the following assertion failure.
OpenCV(3.4.1) Error: Assertion failed ((unsigned)(i1 *
DataType<_Tp>::channels) < (unsigned)(size.p[1] * channels())) in
cv::Mat::at, file
C:\OpenCV\opencv-3.4.1\modules\core\include\opencv2/core/mat.inl.hpp,
line 1107
Tried to follow the error and found that it was caused by the prepDataStructsfuntion of the edge boxes class. The code of the function is given below.
I have tried changing
for (i = 0; i < n; i++) _sDone.at<int>(0,i) = -1;
to
for (i = 0; i < n; i++) _sDone.at<int>(i,0) = -1;
but the problem remains.
void EdgeBoxesImpl::prepDataStructs(Mat &edgeMap)
{
int y, x, i;
// create _segIImg
Mat E1 = Mat::zeros(w, h, DataType<float>::type);
for (i=0; i < _segCnt; i++)
{
if (_segMag[i] > 0) E1.at<float>(_segP[i].x, _segP[i].y) = _segMag[i];
}
_segIImg = Mat::zeros(w+1, h+1, DataType<float>::type);
_magIImg = Mat::zeros(w+1, h+1, DataType<float>::type);
for (x=1; x < w; x++)
{
const float *e_ptr = edgeMap.ptr<float>(x);
const float *e1_ptr = E1.ptr<float>(x);
const float *si0_ptr = _segIImg.ptr<float>(x);
float *si1_ptr = _segIImg.ptr<float>(x+1);
const float *mi0_ptr = _magIImg.ptr<float>(x);
float *mi1_ptr =_magIImg.ptr<float>(x+1);
for (y=1; y < h; y++)
{
// create _segIImg
si1_ptr[y+1] = e1_ptr[y] + si0_ptr[y+1] + si1_ptr[y] - si0_ptr[y];
float e = e_ptr[y] > _edgeMinMag ? e_ptr[y] : 0;
// create _magIImg
mi1_ptr[y+1] = e +mi0_ptr[y+1] + mi1_ptr[y] - mi0_ptr[y];
}
}
// create remaining data structures
int s = 0;
int s1;
_hIdxs.resize(h);
_hIdxImg = Mat::zeros(w, h, DataType<int>::type);
for (y = 0; y < h; y++)
{
s = 0;
_hIdxs[y].push_back(s);
for (x = 0; x < w; x++)
{
s1 = _segIds.at<int>(x, y);
if (s1 != s)
{
s = s1;
_hIdxs[y].push_back(s);
}
_hIdxImg.at<int>(x, y) = (int)_hIdxs[y].size() - 1;
}
}
_vIdxs.resize(w);
_vIdxImg = Mat::zeros(w, h, DataType<int>::type);
for (x = 0; x < w; x++)
{
s = 0;
_vIdxs[x].push_back(s);
for (y = 0; y < h; y++)
{
s1 = _segIds.at<int>(x, y);
if (s1 != s)
{
s = s1;
_vIdxs[x].push_back(s);
}
_vIdxImg.at<int>(x, y) = (int)_vIdxs[x].size() - 1;
}
}
// initialize scoreBox() data structures
int n = _segCnt + 1;
_sWts = Mat::zeros(n, 1, DataType<float>::type);
_sDone = Mat::zeros(n, 1, DataType<int>::type);
_sMap = Mat::zeros(n, 1, DataType<int>::type);
_sIds = Mat::zeros(n, 1, DataType<int>::type);
for (i = 0; i < n; i++) _sDone.at<int>(0, i) = -1;
_sId = 0;
}
After changing in the src file it is required to rebuild the OpenCV library and link it to the project.

load cv::mat to faster rcnn blob

Currently I am working with Faster RCNN using C++. I am trying to load cv Mat object (color image) to the net_->blob_by_name("data"). I follow the given instruction here https://github.com/YihangLou/FasterRCNN-Encapsulation-Cplusplus but the result is really bad:
I didn't change anything from the original code. So I suspect loading data to blob might be the issue.
Code:
float im_info[3];
float data_buf[height*width*3];
float *boxes = NULL;
float *pred = NULL;
float *pred_per_class = NULL;
float *sorted_pred_cls = NULL;
int *keep = NULL;
const float* bbox_delt;
const float* rois;
const float* pred_cls;
int num;
for (int h = 0; h < cv_img.rows; ++h )
{
for (int w = 0; w < cv_img.cols; ++w)
{
cv_new.at<cv::Vec3f>(cv::Point(w, h))[0] = float(cv_img.at<cv::Vec3b>(cv::Point(w, h))[0])-float(102.9801);
cv_new.at<cv::Vec3f>(cv::Point(w, h))[1] = float(cv_img.at<cv::Vec3b>(cv::Point(w, h))[1])-float(115.9465);
cv_new.at<cv::Vec3f>(cv::Point(w, h))[2] = float(cv_img.at<cv::Vec3b>(cv::Point(w, h))[2])-float(122.7717);
}
}
cv::resize(cv_new, cv_resized, cv::Size(width, height));
im_info[0] = cv_resized.rows;
im_info[1] = cv_resized.cols;
im_info[2] = img_scale;
for (int h = 0; h < height; ++h )
{
for (int w = 0; w < width; ++w)
{
data_buf[(0*height+h)*width+w] = float(cv_resized.at<cv::Vec3f>(cv::Point(w, h))[0]);
data_buf[(1*height+h)*width+w] = float(cv_resized.at<cv::Vec3f>(cv::Point(w, h))[1]);
data_buf[(2*height+h)*width+w] = float(cv_resized.at<cv::Vec3f>(cv::Point(w, h))[2]);
}
}
net_->blob_by_name("data")->Reshape(1, 3, height, width);
net_->blob_by_name("data")->set_cpu_data(data_buf);
net_->blob_by_name("im_info")->set_cpu_data(im_info);
net_->ForwardFrom(0);
bbox_delt = net_->blob_by_name("bbox_pred")->cpu_data();
num = net_->blob_by_name("rois")->num();
Any advices ?
Can you please modify the code and check ...
cv::resize(cv_new, cv_resized, cv::Size(width, height));
im_info[0] = cv_resized.rows;
im_info[1] = cv_resized.cols;
im_info[2] = img_scale;
net_->blob_by_name("data")->Reshape(1, 3, height, width);
const shared_ptr<Blob<float> >& data_blob = net_->blob_by_name("data");
float* data_buf = data_blob->mutable_cpu_data();
for (int h = 0; h < height; ++h )
{
for (int w = 0; w < width; ++w)
{
data_buf[(0*height+h)*width+w] = float(cv_resized.at<cv::Vec3f> cv::Point(w, h))[0]);
data_buf[(1*height+h)*width+w] = float(cv_resized.at<cv::Vec3f>(cv::Point(w, h))[1]);
data_buf[(2*height+h)*width+w] = float(cv_resized.at<cv::Vec3f>(cv::Point(w, h))[2]);
}
}
net_->Forward();

openCV creating a 3D matrix with different sizes

accroding to this
http://answers.opencv.org/question/15917/how-to-access-data-from-a-cvmat/
I have tried to create a 3D matrix
void AutomaticMacbethDetection::DrawMacbethROI(ColorCheckerBatchRGB ColorCheckerBatchRGB, int *** raw_frame,int _width, int _height,int colorOrder)
{
cv::Mat src;
if (colorOrder == -1)
{
const int sizes[3]={_height,_width,3};
src = cv::Mat::zeros(3, sizes, CV_32F);
}else
{
const int sizes[3]={_height,_width,1};
src = cv::Mat::zeros(3, sizes, CV_32F);
}
std::vector<float> channel;
if (colorOrder == -1)
{
for (int w = 0; w < _width; w++)
{
for (int h = 0; h < _height; h++)
{
float temp =raw_frame[h][w][0];
channel.push_back(temp);
src.at<float>(h,w,0) = temp;
src.at<float>(h,w,1) = raw_frame[h][w][1];
src.at<float>(h,w,2) = raw_frame[h][w][2];
}
}
}
else
{
for (int w = 0; w < _width; w++)
{
for (int h = 0; h < _height; h++)
{
float temp =raw_frame[h][w][0];
channel.push_back(temp);
src.at<float>(h,w,0) = temp;
}
}
float divider = Utilities::tprctile(channel,99.2);
src = src/divider;
}
cv::imshow("test", src);
cv::waitKey(0);
}
my function supports both RGB and Raw Image so I need to create a 100x100x1 matrix or a 100x100x3 matrix, depending on the image type.
however I get an exception in imshow()
OpenCV Error: Assertion failed (p[-1] <= 2) in cv::Mat::MSize::operator (), file
C:\buildslave64\win64_amdocl\2_4_PackSlave-win64-vc11-shared\opencv\modules\cor
e\include\opencv2/core/mat.hpp, line 712
can you please explain what is the problem?
It looks to me that you are trying to set a 3-layer zero mat in both cases:
const int sizes[3]={_height,_width,1};
src = cv::Mat::zeros(3, sizes, CV_32F);
C++: static MatExpr Mat::zeros(int ndims, const int* sz, int type) states that the first argument is the dimentions. This should here be 1 if you want a 1-layer mat.
The solution I have found for this is using CV_32FC3 which means each cell of the matrix (x,y) has 3 values in it.
this is how you init the 3D matrix.
src = cv::Mat::zeros(_height,_width, CV_32FC3);
and now you have 3 cells which you need to access like so:
src.at<cv::Vec3f>(h,w)[0]
src.at<cv::Vec3f>(h,w)[1]
src.at<cv::Vec3f>(h,w)[2]
Please notice I'm using Vec3f and not float like i'm using in CV_32F
void AutomaticMacbethDetection::DrawMacbethROI(ColorCheckerBatchRGB ColorCheckerBatchRGB, int *** raw_frame,int _width, int _height,int colorOrder)
{
cv::Mat src;
std::vector<float> channel;
if (colorOrder != -1 )
{
src = cv::Mat::zeros(_height,_width, CV_32F);
for (int w = 0; w < _width; w++)
{
for (int h = 0; h < _height; h++)
{
float temp =raw_frame[h][w][0];
channel.push_back(temp);
src.at<float>(h,w) = temp;
}
}
float divider = Utilities::tprctile(channel,99.2);
src = src/divider;
}
else
{
src = cv::Mat::zeros(_height,_width, CV_32FC3);
for (int w = 0; w < _width; w++)
{
for (int h = 0; h < _height; h++)
{
float temp =raw_frame[h][w][0];
channel.push_back(temp);
src.at<cv::Vec3f>(h,w)[0] = raw_frame[h][w][0];
src.at<cv::Vec3f>(h,w)[1] = raw_frame[h][w][1];
src.at<cv::Vec3f>(h,w)[2] = raw_frame[h][w][2];
}
}
float divider = Utilities::tprctile(channel,99.2);
src = src/divider;
}
cv::resize(src,src,cv::Size(),0.3,0.3,cv::INTER_LINEAR);
cv::imshow("detected", src);
cv::waitKey(0);

Mandelbrot draw method

I have the assignment to finish a mandelbrot program in C++. I'm not that good in C++, I prefer Java or C# but this has to be done in C++. I got some sample code which I have to finish. I'm trying to put the drawing code in the main (between the works comments) into a method (draw_Mandelbrot). The code in the main method works and gives me a nice mandelbrot image but when I use the draw_Mandelbrot method (and comment the draw code in main) I get a grey rectangle image as output. How can I make the draw_Mandelbrot method work? The code above the draw_Mandelbrot method is all sample code and not created by myself.
// mandelbrot.cpp
// compile with: g++ -std=c++11 mandelbrot.cpp -o mandelbrot
// view output with: eog mandelbrot.ppm
#include <fstream>
#include <complex> // if you make use of complex number facilities in C++
#include <iostream>
#include <cstdlib>
#include <complex>
using namespace std;
template <class T> struct RGB { T r, g, b; };
template <class T>
class Matrix {
public:
Matrix(const size_t rows, const size_t cols) : _rows(rows), _cols(cols) {
_matrix = new T*[rows];
for (size_t i = 0; i < rows; ++i) {
_matrix[i] = new T[cols];
}
}
Matrix(const Matrix &m) : _rows(m._rows), _cols(m._cols) {
_matrix = new T*[m._rows];
for (size_t i = 0; i < m._rows; ++i) {
_matrix[i] = new T[m._cols];
for (size_t j = 0; j < m._cols; ++j) {
_matrix[i][j] = m._matrix[i][j];
}
}
}
~Matrix() {
for (size_t i = 0; i < _rows; ++i) {
delete [] _matrix[i];
}
delete [] _matrix;
}
T *operator[] (const size_t nIndex)
{
return _matrix[nIndex];
}
size_t width() const { return _cols; }
size_t height() const { return _rows; }
protected:
size_t _rows, _cols;
T **_matrix;
};
// Portable PixMap image
class PPMImage : public Matrix<RGB<unsigned char> >
{
public:
PPMImage(const size_t height, const size_t width) : Matrix(height, width) { }
void save(const std::string &filename)
{
std::ofstream out(filename, std::ios_base::binary);
out <<"P6" << std::endl << _cols << " " << _rows << std::endl << 255 << std::endl;
for (size_t y=0; y<_rows; y++)
for (size_t x=0; x<_cols; x++)
out << _matrix[y][x].r << _matrix[y][x].g << _matrix[y][x].b;
}
};
void draw_Mandelbrot(PPMImage image, const unsigned width, const unsigned height, double cxmin, double cxmax, double cymin, double cymax,unsigned int max_iterations)
{
for (std::size_t ix = 0; ix < width; ++ix)
for (std::size_t iy = 0; iy < height; ++iy)
{
std::complex<double> c(cxmin + ix / (width - 1.0)*(cxmax - cxmin), cymin + iy / (height - 1.0)*(cymax - cymin));
std::complex<double> z = 0;
unsigned int iterations;
for (iterations = 0; iterations < max_iterations && std::abs(z) < 2.0; ++iterations)
z = z*z + c;
image[iy][ix].r = image[iy][ix].g = image[iy][ix].b = iterations;
}
}
int main()
{
const unsigned width = 1600;
const unsigned height = 1600;
PPMImage image(height, width);
//image[y][x].r = image[y][x].g = image[y][x].b = 255; // white pixel
//image[y][x].r = image[y][x].g = image[y][x][b] = 0; // black pixel
//image[y][x].r = image[y][x].g = image[y][x].b = 0; // black pixel
//// red pixel
//image[y][x].r = 255;
//image[y][x].g = 0;
//image[y][x].b = 0;
draw_Mandelbrot(image, width, height, -2.0, 0.5, -1.0, 1.0, 10);
//works
//double cymin = -1.0;
//double cymax = 1.0;
//double cxmin = -2.0;
//double cxmax = 0.5;
//unsigned int max_iterations = 100;
//for (std::size_t ix = 0; ix < width; ++ix)
// for (std::size_t iy = 0; iy < height; ++iy)
// {
// std::complex<double> c(cxmin + ix / (width - 1.0)*(cxmax - cxmin), cymin + iy / (height - 1.0)*(cymax - cymin));
// std::complex<double> z = 0;
// unsigned int iterations;
// for (iterations = 0; iterations < max_iterations && std::abs(z) < 2.0; ++iterations)
// z = z*z + c;
// image[iy][ix].r = image[iy][ix].g = image[iy][ix].b = iterations;
// }
//works
image.save("mandelbrot.ppm");
return 0;
}
Output image when using the code in the main method
You're passing the image by value, so the function works on a separate image to the one in main, which is left in its initial state.
Either pass by reference:
void draw_Mandelbrot(PPMImage & image, ...)
or return a value:
PPMImage draw_Mandelbrot(...) {
PPMImage image(height, width);
// your code here
return image;
}
// in main
PPMImage image = draw_Mandelbrot(...);