Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a caffe.io.write_mean function to the MATLAB interface #3058

Merged
merged 1 commit into from
Oct 5, 2015

Conversation

zoharby
Copy link

@zoharby zoharby commented Sep 11, 2015

Useful for exporting models from MATLAB (e.g. MatConvNet) to Caffe

mxCHECK(ndims >= 2 && ndims <= 3, "mean_mat must have at 2 or 3 dimensions");
const mwSize *dims = mxGetDimensions(prhs[0]);
int height = dims[0];
int width = dims[1];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you've messed up with dimensions. It should be int width = dims[0]; int height = dims[1];

@zoharby
Copy link
Author

zoharby commented Sep 29, 2015

Actually, MATLAB has a Column-major order, so the order of the dimensions in memory is:
(height, width, channels, num)
and not:
(width, height, channels, num) as mentioned in line 9. So I think actually all the rest of the conventions in the interface are incorrect and should be reversed. But I agree that currently my commit is inconsistent with the rest of the code, so we should align all the functions to the same convention.

Images in MATLAB are definitely stored as HxWxC, so the following is correct:

const mwSize *dims = mxGetDimensions(prhs[0]);
int height = dims[0];
int width = dims[1];
int channels = dims[2];

Did you have any specific reason why you used (width, height, channels, num) for the MATLAB memory layout?

@ronghanghu
Copy link
Member

Actually, MATLAB has a Column-major order, so the order of the dimensions in memory is:
(height, width, channels, num)
and not:
(width, height, channels, num) as mentioned in line 9.

Yes, you are right. There has been a lot of confusion on Caffe's dimensions, so let me try to clarify here.

If you load an image using Matlab's imread, it is going to be (H x W x C, column-major), where H is the fastest (memory continuous) dimension.

However, this characteristic of Matlab's image toolbox (height being the fastest dimension) is inconsistent with many other image tools, such as OpenCV. In OpenCV (both C/C++ and Python), the default memory layout will be (H x W x C, row-major) in C-contiguous array, that is, channel being the fastest dimension, followed by width, and height being the slowest dimension. Since C/C++ is row-major and Matlab is column major, OpenCV's memory layout (H x W x C, row-major) is exactly the opposite from Matlab (H x W x C, column-major).

When designing Caffe, to be consistent with C/C++ and numpy's default, and to make it easier to do convolution with existing BLAS libraries, we adopted (N x C x H x W, row-major) memory layout. This is neither Matlab convention nor OpenCV convention. Also, OpenCV uses BGR channel order by default while Matlab uses RGB channel order, and we follow OpenCV to use BGR in Caffe.

So if you load an image using Matlab's imread, you will need to:

  1. Permute height and width to make width the fastest dimension
  2. Permute channel order from RGB to BGR
  3. Convert from uint8 to (single precision) float
    as is illustrated in caffe.io.load_image, so that the loaded image can be processed by Caffe's C++ functions.

In your code above, to make the mean protobinary consistent with the rest of Caffe and loadable by Caffe's data layers, you will need to set

int width = dims[0];
int height = dims[1];
int channels = dims[2];

And remember convert dimensions to (W x H x C, column-major), channel order to BGR before running your caffe.io.write_mean

@zoharby
Copy link
Author

zoharby commented Oct 4, 2015

Right, my mistake, thanks for the clear & detailed explanation.
I now realize the conversion to WxHxC BGR is even demonstrated in the classification_demo.m file and in load_image as you mentioned.

Fixed & Pushed, I think it's all good now.

@ronghanghu
Copy link
Member

@zoharby Please squash into one single commit, and I'll merge.

// Usage: caffe_('write_mean', mean_mat, mean_proto_file)
static void write_mean(MEX_ARGS) {
mxCHECK(nrhs == 2 && mxIsSingle(prhs[0]) && mxIsChar(prhs[1]),
"Usage: caffe_('write_mean', mean_mat, mean_proto_file)");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to be consistent with matlab code in nomination here and use 'mean_data' instead of 'mean_mat'.

@zoharby
Copy link
Author

zoharby commented Oct 5, 2015

Fixed the naming you suggested and squashed (took a few attempts but finally figured it out, learning as I ago along...).

Useful for exporting models from MATLAB (e.g. MatConvNet) to Caffe
@ronghanghu
Copy link
Member

Everything looks good now :) @zoharby Thank you for this PR!

ronghanghu added a commit that referenced this pull request Oct 5, 2015
Add a caffe.io.write_mean function to the MATLAB interface
@ronghanghu ronghanghu merged commit 92dc4e6 into BVLC:master Oct 5, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants