Simon
Simon

Reputation: 764

OpenCV N-Channel Image

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

Answers (1)

Mark Setchell
Mark Setchell

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

Related Questions