Я думаю, что правильный ответ - написать код, используя libtiff
. Я не эксперт по libtiff
, но это похоже на те случаи, которые я пробовал:
#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;
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;
// We expect 4 channels
int channels = image.channels();
assert(channels==4);
// We expect 8-bit data
int bytespersample = image.elemSize1();
assert(bytespersample == 1);
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);
// 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
cv::Vec4b* ptr = image.ptr<cv::Vec4b>(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 a 4-channel CMYK yellow image
Mat4b image(480, 640, Vec4b(0,0,255,0));
// Write as CMYK TIFF
tiffwrite("result.tif",image);
}
У меня также есть пара хаков, которые вы можете попробовать.
Первый и самый простой хак, сохраните с помощью OpenCV как обычно в формате JPEG, TIFF или PNG, затем используйте функцию system()
, чтобы выложить в ImageMagick и преобразовать воттуда CMIF TIFF.
cv2::imwrite("intermediate.jpg",image);
system("...");
А внутри вы помещаете эквивалент:
convert intermediate.jpg -colorspace CMYK result.tif
Или, если используете v7 из ImageMagick
magick intermediate.jpg -colorspace CMYK result.tif
Второй хак, если вы не хотите устанавливать и зависите от ImageMagick ... есть инструмент под названием raw2tiff , который поставляется с libtiff
. Вы можете передать ему необработанный файл (без заголовков), и он преобразует его в TIFF для вас. Таким образом, вы в основном будете использовать OpenCV для записи необработанных байтов C, затем необработанных байтов M, затем необработанных байтов Y и необработанных байтов K в один файл и использовать system()
для вызова этой утилиты. Я использовал эту командную строку:
raw2tiff -w 1024 -l 768 -b 4 -i band -c lzw -p cmyk CMYK result.tif
Таким образом, мое изображение имело ширину 1024 пикселя, высоту 768 пикселей, состоящее из 4 полос в файле CMYK
, и я хотел сжать TIFF со сжатием LZW, который называется result.tif
. В Photoshop это выглядит так:
Я сделал синтетические каналы C, M, Y и K с ImageMagick какэто:
#!/bin/bash
# Make raw and viewable C channel
convert -size 1024x768 gradient: -depth 8 -write gray:C C.png
# Make raw and viewable M channel
convert -size 1024x768 xc:black -depth 8 -write gray:M M.png
# Make raw and viewable Y channel
convert -size 768x1024 gradient: -rotate 90 -depth 8 -write gray:Y Y.png
# Make raw and viewable K channel
convert -colorspace RGB -size 400x400 gradient: -gravity center -background black -extent 1024x768 -depth 8 -write gray:K K.png
# Stack side-by-side, just for viewing
convert C.png M.png Y.png K.png +append CMYK.png
# Concatenate them all together into single file "CMYK" as input file for "raw2tiff"
cat C M Y K > CMYK
Вот 4 изображения, добавленные рядом с C слева, затем M, затем Y и, наконец, с K справа.
В вашем случае вы получите указатель data
на ваш Mat
и просто запишите байты высоты * ширины для каждого канала в двоичный файл вместо использования ImageMagick . Вы можете увидеть, как это сделать, в примере libtiff
в верхней части моего ответа.
Ключевые слова : TIFF, TIF, обработка изображений, libtiff, CMYK, цветоделение, цветоделение, Photoshop.
Глядя на изображение, я думаю, мне следовало сначала отрицать (перевернуть) изображение, но это не так уж сложно.