Как создать образ в режиме CMYK в C ++? - PullRequest
1 голос
/ 29 октября 2019

Я недавно работаю над opencv. И мне нужно создать мат изображения и записать его в файл изображения .tif. Файл .tif должен быть в режиме CMYK, когда он открывается в фотошопе для печати. ​​

Но когда я пытался imread файл изображения CMYK с типом UNCHANGED, а затем imwrite мат в .tifфайл, это все еще режим RGB в фотошопе.

Сохраняется ли изображение только в режиме RGB (или BGR) с помощью opencv? (Я нашел несколько ответов, что у python есть библиотека, которая может выбрать режим CMYK для сохранения. Но я хочу знать, есть ли способ решить эту проблему в C ++?)


Спасибо @Mark. Я сталкиваюсь с некоторыми проблемами, когда пытаюсь скомпилировать библиотеку libtiff в windows10.

Загружаю libtiff с версией tiff-4.0.10.zip. И используйте nmake /f makefile.vc для компиляции в vs2017. (без каких-либо изменений в nmake.opt).

Тогда получите файл .dll .lib. Свяжите libtiff_i.lib с папкой библиотеки и файлами слушателей, чтобы включить папку в проект.

Попробуйте тестовый код @Mark. Затем я сталкиваюсь с ошибкой (LNK2019) в vs, которая выглядит как проблема со связью.

LNK2019 unresolved external symbol TIFFClose referenced in function "bool __cdecl tiffwrite(char const *,class cv::Mat)" (?tiffwrite@@YA_NPEBDVMat@cv@@@Z)  
LNK2019 unresolved external symbol TIFFSetField referenced in function "bool __cdecl tiffwrite(char const *,class cv::Mat)" (?tiffwrite@@YA_NPEBDVMat@cv@@@Z)       
LNK2019 unresolved external symbol TIFFWriteScanline referenced in function "bool __cdecl tiffwrite(char const *,class cv::Mat)" (?tiffwrite@@YA_NPEBDVMat@cv@@@Z)  
LNK2019 unresolved external symbol TIFFOpen referenced in function "bool __cdecl tiffwrite(char const *,class cv::Mat)" (?tiffwrite@@YA_NPEBDVMat@cv@@@Z)

Я не уверен, что это проблема со связью или проблема скомпилированного файла (libtiff.dll, libtiff_i.lib)?

(Вот настройки ссылок в vs2017: linker lib и включите


Я исправляю эту проблему с помощью cmake для компиляции libtiff.

Следуйте этому Справочная информация может получить нужную библиотеку для vs2017 в Windows (64-разрядная версия).

1 Ответ

2 голосов
/ 29 октября 2019

Я думаю, что правильный ответ - написать код, используя 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 это выглядит так:

enter image description here

Я сделал синтетические каналы 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 справа.

enter image description here

В вашем случае вы получите указатель data на ваш Mat и просто запишите байты высоты * ширины для каждого канала в двоичный файл вместо использования ImageMagick . Вы можете увидеть, как это сделать, в примере libtiff в верхней части моего ответа.

Ключевые слова : TIFF, TIF, обработка изображений, libtiff, CMYK, цветоделение, цветоделение, Photoshop.

Глядя на изображение, я думаю, мне следовало сначала отрицать (перевернуть) изображение, но это не так уж сложно.

...