Как преобразовать PNG-изображение глубиной от 24 до 8 бит, используя OpenCV C ++ - PullRequest
0 голосов
/ 22 февраля 2019

Я хочу преобразовать 24-битные PNG-изображения в 8-битные PNG-изображения

Я испробовал несколько методов, но они потерпели неудачу.

Я хочу преобразовать цвет 24-bit png_images в color 8-bit png_images

Однако, если я пытаюсь преобразовать в 8-битное изображение, становится серой шкалой.

Я хочу использовать imwrite (). Но ничего не имеет значения.

Ниже приведен мой полный код.

#include <oppencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp> //for resize
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <stdio.h>

using namespace cv;
using namespace std;

void overlayImage(const Mat &background, const Mat &foreground, Mat &output, 
Point2i location);

int main(int argc, char** argv)
{

    Mat image_background;
    Mat black_background;
    Mat image_target, image_segmentation;

    image_target = imread("panda.png", IMREAD_UNCHANGED);   //  Transparent PNG


    image_segmentation = imread("panda_segmentation_stroke.png", IMREAD_UNCHANGED);

    string filename, filename2;

    vector<String> fn;

    glob("C:\\Users\\IMRC\\source\\repos\\OpenCVProject\\OpenCVProject\\background\\*.jpg", fn, false);

    size_t count = fn.size();
    cout << "Image Size " << count << "\n";

    float MIN_SIZE = 0.3;
    float MAX_SIZE = 0.8;

    float WIDTH = 300;
    float HEIGHT = 400;
    float SIZE_WIDTH, SIZE_HEIGHT, Point_x, Point_y;  // random size and point 


    string JPEGImagesPath = "C:\\Users\\IMRC\\DESKTOP\\TEST\\JPEGImages\\2019-";
    string SEG_ImagesPath = "C:\\Users\\IMRC\\DESKTOP\\TEST\\SegmentationClass\\2019-";

    srand(static_cast <unsigned> (time(0)));

    black_background = imread(fn[0], IMREAD_COLOR);
    resize(black_background, black_background, Size(500, 500));

    for (size_t i = 0; i < count; i++) {
        cout << fn[i] << "\n";

        image_background = imread(fn[i], IMREAD_COLOR);                           
        black_background.setTo(Scalar(0, 0, 0));

        resize(image_background, image_background, Size(500,500));                    // background image resize

        Mat image_resize_target;
        Mat image_resize_segmentation;


        SIZE_WIDTH = MIN_SIZE + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX / (MAX_SIZE - MIN_SIZE)));
        SIZE_HEIGHT = MIN_SIZE + static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / (MAX_SIZE - MIN_SIZE)));

        Point_x = static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / WIDTH));
        Point_y = static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / HEIGHT));

        resize(image_target, image_resize_target, Size(), SIZE_WIDTH, SIZE_HEIGHT);                
        resize(image_segmentation, image_resize_segmentation, Size(), SIZE_WIDTH, SIZE_HEIGHT);

        overlayImage(image_background, image_resize_target, image_background, cv::Point(Point_x, Point_y));
        overlayImage(black_background, image_resize_segmentation, black_background, cv::Point(Point_x, Point_y));


        stringstream JPEGImages, SEG_Images, SEG_RawImage;
        JPEGImages   << JPEGImagesPath    << i + 1 << ".jpg";
        SEG_Images   << SEG_ImagesPath    << i + 1 << ".png";

        filename = JPEGImages.str();
        imwrite(filename, image_background);  // save JPEGImages

        filename2 = SEG_Images.str();   
        imwrite(filename2, black_background); // save SegmentationClass

    }

    return 0;
}

void overlayImage(const Mat &background, const Mat &foreground, Mat &output, Point2i location)
{
    background.copyTo(output);

    // start at the row indicated by location, or at row 0 if location.y is negative.
    for (int y = std::max(location.y, 0); y < background.rows; ++y)
    {
    int fY = y - location.y;   // because of the translation

    if (fY >= foreground.rows) // we are done of we have processed all rows of the foreground image.
        break;

    // start at the column indicated by location, 

    // or at column 0 if location.x is negative.
    for (int x = std::max(location.x, 0); x < background.cols; ++x)
    {
        int fX = x - location.x;    // because of the translation.

        if (fX >= foreground.cols)  // we are done with this row if the column is outside of the foreground image.
            break;

        // determine the opacity of the foregrond pixel, using its fourth (alpha) channel.
        double opacity = ((double)foreground.data[fY * foreground.step + fX * foreground.channels() + 3]) / 255.;
            // and now combine the background and foreground pixel, using the opacity, 

            // but only if opacity > 0.
            for (int c = 0; opacity > 0 && c < output.channels(); ++c)
            {
                unsigned char foregroundPx = foreground.data[fY * foreground.step + fX * foreground.channels() + c];
                unsigned char backgroundPx = background.data[y * background.step + x * background.channels() + c];
                output.data[y*output.step + output.channels()*x + c] = backgroundPx * (1. - opacity) + foregroundPx * opacity;
            }
        }
    }
}

Цель этого кодадля синтеза.

После подготовки фоновых изображений и другого png_images, а также экспорта составного изображения.

Я хочу напечатать это изображение как 8-битное цветное изображение png.

Как изменить исходный код?

Добавить изображение Введите описание изображения здесь

1 Ответ

0 голосов
/ 22 февраля 2019

Вы можете использовать функцию Mat :: convertTo , чтобы изменить тип вашего cv::Mat.Я предполагаю, что изображение, которое вы хотите преобразовать в 8-битное, имеет тип CV_32SC3 (или CV_32SC4, если у вас есть альфа-канал).Даже если мое предположение неверно, вы можете узнать правильный тип изображения, используя cv :: Mat :: type () .Затем вы можете преобразовать ваше изображение в CV_8UC3, используя первую функцию выше.Обратите внимание, что функция преобразования принимает коэффициент масштабирования alpha.Это должно быть установлено правильно, что в противном случае могло бы вызвать переполнение целых чисел.Вы можете определить правильный коэффициент масштабирования в соответствии с тем, что дает вам cv::Mat::type().Надеюсь, это поможет!

Редактировать: Вы можете проверить, что означает результат type() здесь .

Синопсис cv :: imwrite говоритединственным параметром, который можно настроить, является качество изображения при записи файла PNG.Изменение количества каналов вашего изображения OpenCV - единственный второй способ установить свойства изображения, которые мы уже обсуждали выше.В результате получение 8-битного цвета PNG возможно только с помощью палитры.Проверьте документацию libpng, где написано Если вы пишете изображение с индексированными цветами, вы должны предоставить палитру (цветовую карту) .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...