RGB数据的处理

RGB数据的处理

基本概念

分辨率为640*480的图像,其像素点的个数为 widthxheight,即为640x480 = 307200

  1. 二值图像
    每个像素通过一位来存储即为二值图,取值只有0和1。
  2. 灰度图像
    在二值图像中加入许多介于黑色与白色之间的颜色深度,就构成了灰度图像,就典型的就是256色图,像素取值可以是0到255之间的整数值,那么每个像素占一个字节即8位,灰度图反映的是该图像的亮度信息,灰度级为0~255。占用内存的大小为widthxheight。
  3. RGB24图像
    每个像素占三个字节,对应于Red,Green,Blue三原色值,每个原色的取值是0到 255间的整数。这样的图也称为rgb24,24位真彩色。占用内存的大小为widthxheightx3

数字图像的表示

为了表述像素之间的相对和绝对位置,可以把图像看一个原点在左上角的二维坐标系。如下图
这里写图片描述

那么一副物理图像就被转化成了数字矩阵,成为了计算机能够处理的对象。
这里写图片描述

为M行N列的矩阵,对应的就是Height行width列的矩阵。

rgb图像在程序中的表示

  • 二维矩阵在C++中映射的就是二维数组。对分辨率为w*h的图像,可以在程序中定义
unsigned char imag[Height][width]

来表示。这里的imag是表示指向元素个数为width类型为unsigned char的数组的指针,unsigned char (*img)[width]。

  • 动态分配存放图像数据的二维数组的代码示例如下:
//指针的指针
unsigned char** pRGBData = NULL;

//元素个数为Height的unsigned char*数组
pRGBData = new unsigned char*[Height];
for (int i=0; i<Height; ++i)
{
    pRGBData[i] = new unsigned char[width];
}

内存结构示意:
这里写图片描述

rgb内存存储顺序

不同于字面的顺序,rgb数据实际的存储顺序为 BGR,BGR

bmp格式

windows有一种bmp的图像文件格式,它的图像数据就rgb数据,将rgb封装成bmp格式后可以很方便的进行预览。
bmp格式介绍

处理bmp数据涉及到如下两个问题:
1. 在图像处理中的坐标系的原点是在左上角,而bmp数据坐标的原点在左下角。这里涉及到坐标的转换。
2. bmp的数据是需要4字节对齐的,如果不为4字节的整数倍,则是会填充数据的,所以计算图像数据大小时就不能简单的通过width*height*像素字节数来计算,可以通过如下宏计算

// 在计算图像大小时,采用公式:biSizeImage = biWidth' × biHeight。
// 是biWidth',而不是biWidth,这里的biWidth'必须是4的整倍数,表示
// 大于或等于biWidth的,离4最近的整倍数。WIDTHBYTES就是用来计算
// biWidth'
#define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4)
//这里计算的是rgb24的行说占的字节数
int nWidthBytes = WIDTHBYTES(iWidth*24);

示例程序

下面实现了一个rgb24处理类,包含如下功能:
1. 加载rgb24数据文件,这里的rgb数据文件并非指bmp文件,而指只有rgb数据的文件。
2. 获取/设置指定像素的值。
3. 获取指定像素的灰度值。
4. 将rgb24数据文件存成bmp格式文件。
5. 在rgb24图像上画线。

#include <stdio.h>
#include <string>
#include <Windows.h>
//#define RGB(r,g,b) ((unsigned long)(((unsigned char)(r)|((unsigned short)((unsigned char)(g))<<8))|(((unsigned long)(unsigned char)(b))<<16)))
#define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4)

class CProcessRGB
{
public:
    CProcessRGB() :m_pRGBFile(NULL), m_iHeight(0),m_iWidth(0), m_pRGBData(NULL),m_pBmpFile(NULL)
    {

    }

    ~CProcessRGB()
    {
        if (NULL != m_pRGBFile)
        {
            fclose(m_pRGBFile);
            m_pRGBFile = NULL;
        }

        if (NULL != m_pRGBData)
        {
            for (int i = 0; i < m_iHeight; ++i)
            {
                if (NULL != m_pRGBData[i])
                {
                    delete[] m_pRGBData[i];
                    m_pRGBData[i] = NULL;
                }
            }
        }

        m_pRGBData = NULL;
    }

    int Init(int iWidth,int iHeight,const std::string& strRGBFile)
    {
        m_iWidth = iWidth;
        m_iHeight = iHeight;
        m_pRGBFile = fopen(strRGBFile.c_str(), "rb");
        m_pRGBData = new unsigned char*[iHeight];

        // 读取图像数据,WIDTHBYTES宏用于生成每行字节数
        int nWidthBytes = WIDTHBYTES(iWidth*24);

        for (int i = 0; i < iHeight; ++i)
        {
            m_pRGBData[i] = new unsigned char[nWidthBytes];
            fread(m_pRGBData[i], nWidthBytes, 1, m_pRGBFile);
        }

        return 0;
    }

    //获取指定像素点的颜色值
    unsigned long GetPixel(int x, int y)
    {
        unsigned long color = RGB(m_pRGBData[m_iHeight - y - 1][x * 3 + 2],
            m_pRGBData[m_iHeight - y - 1][x * 3 + 1],
            m_pRGBData[m_iHeight - y - 1][x * 3]);

        return color;
    }

    //设置指定像素的颜色值
    void SetPixel(int x, int y, unsigned long color,unsigned char** pData)
    {
        pData[m_iHeight - y - 1][x * 3] = color;
        pData[m_iHeight - y - 1][x * 3 + 1] = color >> 8;
        pData[m_iHeight - y - 1][x * 3 + 2] = color >> 16;
    }

    //计算指定像素点的灰度值
    unsigned char GetGray(int x, int y)
    {
        unsigned long ref = GetPixel(x, y);
        unsigned char r, g, b, byte;
        r = ref;
        g = ref >> 8;
        b = ref >> 16;

        if (r == g && r == b)
            return r;

        double dGray = (0.30*r + 0.59*g + 0.11*b);

        // 灰度化
        byte = (int)dGray;

        return byte;
    }

    void SaveToBmpFile(const std::string& strBmpFile)
    {
        if (NULL != m_pBmpFile)
        {
            fclose(m_pBmpFile);
            m_pBmpFile = NULL;
        }

        m_pBmpFile = fopen(strBmpFile.c_str(), "wb");

        BITMAPINFOHEADER InfoHeader = { 0 };
        BuildInfoHeader(m_iWidth, m_iHeight, 24, InfoHeader);

        BITMAPFILEHEADER bmfHeader = { 0 };
        BuildFileHeader(m_iWidth, m_iHeight, 24, bmfHeader);

        int nWidthBytes = WIDTHBYTES((m_iWidth)*24);
        int iSize = nWidthBytes*m_iHeight;

        fwrite(&bmfHeader, sizeof(BITMAPFILEHEADER), 1, m_pBmpFile);
        fwrite(&InfoHeader, sizeof(BITMAPINFOHEADER), 1, m_pBmpFile);

        //坐标转换
        for (int i = m_iHeight - 1; i>=0 ; --i)
        {
            fwrite(m_pRGBData[i], nWidthBytes, 1, m_pBmpFile);
        }
    }

    //画线 ptStart表示起始点,nLen表示线的长度,nWide表示线的宽度,bHor是横线还是竖线
    void Line(POINT ptStart, int nLen, int nWide, BOOL bHor)
    {
        int i, j;
        DWORD dw = RGB(0, 0, 255);
        if (bHor)
        {
            for (i = ptStart.x; i <= nLen + ptStart.x; i++)
            {
                for (j = 0; j<nWide; j++)
                {
                    SetPixel(i, ptStart.y + j, dw, m_pRGBData);
                }
            }
        }
        else
        {
            for (j = ptStart.y; j <= nLen + ptStart.y; j++)
            {
                for (i = 0; i<nWide; i++)
                {
                    SetPixel(ptStart.x + i, j, dw, m_pRGBData);
                }
            }
        }
    }


private:
    void BuildInfoHeader(LONG lWidth, LONG lHeight, WORD wBitCount, BITMAPINFOHEADER &bitmapInfoHeader)
    {
        LONG lWidthStep = (((lWidth * wBitCount) + 31) & (~31)) / 8;

        bitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
        bitmapInfoHeader.biWidth = lWidth;
        bitmapInfoHeader.biHeight = lHeight;
        bitmapInfoHeader.biPlanes = 0;
        bitmapInfoHeader.biBitCount = wBitCount;
        bitmapInfoHeader.biCompression = BI_RGB;
        bitmapInfoHeader.biSizeImage = lWidthStep * lHeight;
        bitmapInfoHeader.biXPelsPerMeter = 0;
        bitmapInfoHeader.biYPelsPerMeter = 0;
        bitmapInfoHeader.biClrUsed = 0;
        bitmapInfoHeader.biClrImportant = 0;
    }

    void BuildFileHeader(LONG lWidth, LONG lHeight, WORD wBitCount, BITMAPFILEHEADER &bitmapFileHeader)
    {
        LONG lWidthStep = (((lWidth * wBitCount) + 31) & (~31)) / 8;

        bitmapFileHeader.bfType = ((WORD)('M' << 8) | 'B');  //'BM'
        bitmapFileHeader.bfSize = (DWORD) sizeof(BITMAPFILEHEADER) + (DWORD) sizeof(BITMAPINFOHEADER) + lWidthStep * lHeight;
        bitmapFileHeader.bfReserved1 = 0;
        bitmapFileHeader.bfReserved2 = 0;
        bitmapFileHeader.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + (DWORD) sizeof(BITMAPINFOHEADER);
    }

private:
    //存储RGB内存数据的指针
    unsigned char** m_pRGBData;
    FILE *m_pRGBFile;
    FILE *m_pBmpFile;
    int m_iHeight;
    int m_iWidth;
};

int main()
{
    CProcessRGB RGBProcess;
    //读取rgb24图像
    RGBProcess.Init(1280,720,"./preview_rgb24");

    //画一条横线
    POINT p1;
    p1.x = 0;
    p1.y = 359;
    RGBProcess.Line(p1, 1279, 3, true);

    //画一条竖线
    POINT p2;
    p2.x = 639;
    p2.y = 0;
    RGBProcess.Line(p2, 719, 3, false);

    //将rgb24数据存成bmp文件
    RGBProcess.SaveToBmpFile("./preview.bmp");
}

运行结果:
这里写图片描述

rgb原始数据文件下载
https://download.csdn.net/download/mo4776/10589099

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mo4776

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值