如何使用OPENCV C 将24位转换为8位深度PNG图像



我想将24位PNG图像转换为8bit PNG图像

我尝试了几种方法,但它们失败了。

我想将颜色24位PNG_IMAGES转换为颜色8位PNG_IMAGE

但是,如果我尝试转换为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图像。

如何修改源代码?

添加图片在此处输入图像描述

您可以使用MAT ::转换函数来更改cv::Mat的类型。我假设要转换为8位的图像是CV_32SC3型(或CV_32SC4)(如果您有Alpha通道)。即使我的猜测不正确,您也可以使用CV :: Mat :: Type()学习正确的图像类型。然后,您可以使用上面的第一个功能将图像转换为CV_8UC3。请注意,转换功能接受缩放因子alpha。应该正确设置此设置,否则将导致整数溢出。您可以根据cv::Mat::type()给您的正确缩放系数来找出正确的缩放系数。希望这会有所帮助!

编辑:您可以在此处检查type()的结果。

cv :: imwrite的概述说,您可以调整唯一的参数是编写PNG文件时的图像质量。更改OPENCV图像的频道数量是设置我们上面已经讨论过的图像属性的唯一第二种方法。结果,只有通过使用调色板才能获得8位 color png。检查libpng的文档,说明您正在编写索引颜色图像,则应提供调色板(colormap)。

最新更新