【问题标题】:Save RGB image as PPM format将 RGB 图像保存为 PPM 格式
【发布时间】:2018-10-31 18:38:54
【问题描述】:

我正在尝试在 C++ 中创建 RGB 图像。我没有使用任何像 OpenCv 这样的图像库。

首先,我尝试创建灰度图像。我想绘制矩形图像。我在函数中提供参数,如起点、宽度、高度等。这段代码行适用于这个灰度挑战,但我正在尝试将颜色通道增加到 3,如 RGB。然后,我正在设置红色、绿色和蓝色值,但它不起作用。这是我的问题。

我怎样才能正常工作?

  • x => x 坐标的起点
  • y => y 坐标的起点
  • 宽度 => 矩形宽度
  • height => 矩形高度
  • value => RGB 或灰度颜色值

我的代码

Image::Image(int width, int height, int n_channels, int step)
{
    cout << "Image constructor is running!" << endl;
    m_width = width;
    m_height = height;
    m_n_channels = n_channels;

    m_step = m_width*m_n_channels;
    if (m_step < step)
            m_step = step;
    m_data = new uchar[m_step*height];
}


Image* Image::new_gray(int width, int height)
{
    cout << "New gray image is creating!" << endl;
    return new Image(width, height, 1);
}

Image* Image::new_rgb(int width, int height)
{
    cout << "New RGB image is creating!" << endl;
    return new Image(width, height, 3);
} 



void Image::set_rect(int x, int y, int width, int height, uchar value)
{
    if (x < 0) {
        width += x;
        x = 0;
    }

    if (y < 0) {
        height += y;
        y = 0;
    }

    for (int j = y; j < y+height; ++j) {
        if (j >= m_height)
            break;
        uchar* row_data = data(j);
        for (int i = x; i < x+width; ++i) {
            if (i >= m_width)
                break;
            for (int c = 0; c < m_n_channels; ++c)
                if (c == 0) {
                    row_data[i*m_n_channels + c] = value;
                } else if (c == 1) {
                    row_data[i*m_n_channels + c] = value;
                } else if (c == 2) {
                    row_data[i*m_n_channels + c] = value;
                }
        }
    }
}


bool Image::write_pnm(const std::string& filename) const
{
    if (m_n_channels != 1) {
            const string magic_head = "P6";
            ofstream fout;
            string extended_name = filename + ".ppm";
            fout.open(extended_name.c_str(), ios::out | ios::binary);
            fout << magic_head << "\n";
            fout << m_width << " " << m_height << " 255\n";
            for (int y = 0; y < m_height; ++y) {
                    const uchar *row_data = data(y);
                    cout << reinterpret_cast<const char*>(row_data);
                    fout.write(reinterpret_cast<const char*>(row_data), m_width*sizeof(uchar));
            }
            fout.close();
            return true;
    }

    const string magic_head = "P5";
    ofstream fout;
    string extended_name = filename + ".pgm";
    fout.open(extended_name.c_str(), ios::out | ios::binary);
    fout << magic_head << "\n";
    fout << m_width << " " << m_height << " 255\n";
    for (int y = 0; y < m_height; ++y) {
            const uchar *row_data = data(y);
            fout.write(reinterpret_cast<const char*>(row_data), m_width*sizeof(uchar));
    }
    fout.close();

    return true;
}

我的主要功能

#include <cstdlib>
#include <iostream>

#include "image.h"

using std::cout;
using std::endl;
using ceng391::Image;

int main(int argc, char** argv)
{
    Image* gray = Image::new_gray(128, 128);
    cout << "(" << gray->w() << "x" << gray->h() << ") channels: "
         << gray->n_ch() << " step: " << gray->step() << endl;
    gray->set_zero();
    gray->set_rect(32, 32, 64, 64, 255);
    gray->write_pnm("/tmp/test_image");


    Image* rgb_image = Image::new_rgb(128,128);
    cout << "(" << rgb_image->w() << "x" << rgb_image->h() << ") channels: "
         << rgb_image->n_ch() << " step: " << rgb_image->step() << endl;
    rgb_image->set_zero_rgb();
    rgb_image->set_rect(32, 32, 64, 64, 150);
    rgb_image->write_pnm("/tmp/test_image_rgb");


    delete gray;
    delete rgb_image;


    return EXIT_SUCCESS;
}

【问题讨论】:

  • 当您对 P6 执行 fout.write() 时,您只写入与 P5 相同数量的像素,它应该大 3 倍。
  • 您的 set_rect() 方法只需要 1 个值,并且对 R、G 和 B 使用相同的值,因此您只能创建灰度矩形 - 而不是颜色。
  • 是的,你是对的,但我不明白,因为它取决于 P5 和 P6。如果我写到标题“P5”,这个图像是灰度的。如果我写入标题“P6”,则此图像是 RGB,因此当在图像查看器中打开图像时,我可以看到这种差异。我错了吗?
  • 检查文件的大小 - RGB 文件的大小应该是灰色文件的大约 3 倍。
  • 干得好!将您更正的代码作为答案,然后您可以接受自己的答案并获得积分并将解决方案反馈给社区 - 每个人都赢了。祝你的项目好运——如果你遇到困难就回来:-)

标签: c++ image image-processing ppm image-formats


【解决方案1】:

此代码适用于灰度图像,因为灰度图像的像素数与宽度相同。

fout.write(reinterpret_cast<const char*>(row_data), m_width*sizeof(uchar));

但是当我想保存 RGB 图像时,像素数增加了 3 倍。一个像素通过 3 个通道表示,因此需要将一个像素的流大小乘以 3(R、G、B 通道)。

fout.write(reinterpret_cast<const char*>(row_data), m_width*sizeof(uchar)*3);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-04
    • 2022-11-30
    • 2020-02-29
    • 1970-01-01
    • 2011-01-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多