Reputation: 764
I would like to create an 8 channel openCV image using the C++ API:
cv::Mat lookupTable = cv::Mat(height, width, CV_32FC(8), cv::Scalar::all(-1.f));
I get:
external/opencv/modules/core/src/array.cpp:3229: error: (-215:Assertion failed) cn <= 4 in function 'scalarToRawData'
I was pretty sure that OpenCV supports multi channel >4 images. Am I wrong?
Update 1:
Apparently it is related to the initialization value cv::Scalar::all(-1.f)
. That is limited to be a cv::Vec<T,4>
. However,
cv::Vec<float, 8> a = {-1.f, -1.f, -1.f, -1.f, 1.f, -1.f, -1.f, -1.f};
cv::Mat lookupTable = cv::Mat(height, width, CV_32FC(8), a);
is also not supported and fails with the same error.
Update 2:
cv::Mat lookupTable = cv::Mat(height, width, CV_32FC(8));
lookupTable.setTo(-1);
Compiles and runs, but I didn't yet validate if all values are really initialized to -1
.
However, next problem is that cv::imwrite() can't save that image.
Oh man .. it is really a mess!
Update 3: Ok, I can confirm that lookupTable.setTo(-1)
works and all values are initialized accordingly. Also, what works to save that image is going over cv::FileStorage
.
cv::FileStorage fs("lookup.ext", cv::FileStorage::WRITE_BASE64);
fs.write("LUT",lookupTable);
However, this is saved in text format and there seems to be no way to have it stored in a binary format :-(
Update 4:
Ok, appending .gz
to the extension compresses the file.
cv::FileStorage fs("lookup.ext.gz", cv::FileStorage::WRITE_BASE64);
Upvotes: 3
Views: 1531
Reputation: 207415
Ok, I have cobbled together something that gives no errors and appears to be acceptable to the libtiff
tools, but I don't know of any application that can read the created file except the tiff_dump
tool.
I implemented a comment by @haraldK in response to this answer.
#include <iostream>
#include <opencv2/opencv.hpp>
extern "C" {
#define uint64 uint64_hack_
#define int64 int64_hack_
#include "tiffio.h"
#undef uint64
#undef uint64
}
using namespace cv;
typedef Vec<float,8> Vec8f;
bool tiffwrite(const char* name, Mat image){
TIFF* tif = TIFFOpen(name, "w");
if(tif==NULL){
std::cerr << "ERROR: Unable to open output file";
return false;
}
int width = image.cols;
int height = image.rows;
int channels = image.channels();
int bytespersample = image.elemSize1();
// Check what we've got
std::cout << "width: " << width << std::endl;
std::cout << "height: " << height << std::endl;
std::cout << "channels: " << channels << std::endl;
std::cout << "bytespersample: " << bytespersample << std::endl;
const char *ink_names = "Chan0\0Chan1\0Chan2\0Chan3\0Chan4\0Chan5\0Chan6\0Chan7\0";
const int ink_names_size = 48;
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, channels);
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8*bytespersample);
TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 8);
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_SEPARATED);
TIFFSetField(tif, TIFFTAG_INKSET, 2);
TIFFSetField(tif, TIFFTAG_INKNAMES, ink_names_size, ink_names);
// Write to file, 1 scanline at a time
for (int row = 0; row < height; row++) {
std::cerr << "DEBUG: Writing row " << row << std::endl;
// Get pointer to row
Vec8f* ptr = image.ptr<Vec8f>(row);
int ret = TIFFWriteScanline(tif, (unsigned char*)ptr, row, 0);
if (ret == -1) {
TIFFClose(tif);
return false;
}
}
TIFFClose(tif);
return true;
}
int
main(int argc,char*argv[])
{
// Create an 8-channel image of floats
cv::Mat multichannel(800, 600, CV_32FC(8));
// Check number of channels
std::cout << "Channels: " << multichannel.channels() << std::endl;
// Save as TIFF
tiffwrite("result.tif",multichannel);
}
The tiff dump
utility seems happy enough with the file:
tiffdump result.tif
result.tif:
Magic: 0x4949 <little-endian> Version: 0x2a <ClassicTIFF>
Directory 0: offset 66408 (0x10368) next 0 (0)
ImageWidth (256) SHORT (3) 1<600>
ImageLength (257) SHORT (3) 1<800>
BitsPerSample (258) SHORT (3) 8<32 32 32 32 32 32 32 32>
Compression (259) SHORT (3) 1<5>
Photometric (262) SHORT (3) 1<5>
StripOffsets (273) LONG (4) 100<8 672 1336 2000 2664 3328 3992 4656 5320 5984 6648 7312 7976 8640 9304 9968 10632 11296 11960 12624 13288 13952 14616 15280 ...>
SamplesPerPixel (277) SHORT (3) 1<8>
RowsPerStrip (278) SHORT (3) 1<8>
StripByteCounts (279) LONG (4) 100<664 664 664 664 664 664 664 664 664 664 664 664 664 664 664 664 664 664 664 664 664 664 664 664 ...>
PlanarConfig (284) SHORT (3) 1<1>
InkSet (332) SHORT (3) 1<2>
InkNames (333) ASCII (2) 48<Chan0\0Chan1\0Chan2\0Chan3\0 ...>
Upvotes: 1