(二)OpenCV 通过修改内存图像实现颜色过渡效果

概述:

本例程为利用OpenCV通过操控内存数据,创建一个光滑渐变的图像。

我们会知道如何对图像数据进行访问修改以及操作。

 

核心内容实践:

Step:1: 如何访问指定坐标处的像素点

我们创建的内存图像数组可以记住图像进行理解

由于每个像素有三个通道,那么指定坐标处的数组索引就变成了 像素索引 = (y * width * x) * 通道数。定位到该像素索引之后,我们便可以去按照像素格式,逐通道的进行像素更改,利用指针,我们可以很优雅的实现这个逻辑。

/************************************
*
*  操控指定内存图像指定位置的像素值
*
************************************/
bool SetBGRPixel(unsigned char* pImage,int x,int y, int nWidth, int nHeight, unsigned char R, unsigned G, unsigned B)
{
    //nPixelIndex,定位到指定位置的内存图像的索引,第Y行,第X列
    int nPixelIndex = (y * nWidth + x) * 3;
    //赋值像素位置B通道参数
    pImage[nPixelIndex  ]   = B;
    //赋值像素位置G通道参数
    pImage[nPixelIndex + 1] = G;
    //赋值像素位置R通道参数
    pImage[nPixelIndex + 2] = R;
    return true;
}

Step:2: 如何创建一个平滑的像素渐变

关于如何平滑的过渡,我们可以看下面这个图,对距离和像素进行插值计算。

插值的思想在图形图像中经常会遇到,通过合理的插值,我们可以模拟出很多中间过程而不用逐个的去求中间每个值。

我们知道A的值,也知道B处的值,那么求得一个A,B之间的平滑的过渡区域那就是在我们要走的这么多步之中,每次都恰好走了一个step,由于内存像素只认整数,在step的过程中需要用一个浮点数来记录当前步进到多少,然后用的时候将这个值规整到指定像素值。

//计算行渐变的步进值,double类型保留了精度
double nPixelColorAdd = 255.0 / nIMGWidth;
//遍历内存图像数组的height
for (int nYIndex = 0; nYIndex < nIMGHeight; nYIndex++)
{
    //定义步进图像的像素值通道参数
    double dRValue = 0.0;
    double dGValue = 0.0;
    double dBValue = 0.0;
    //遍历内存图像数组的width
    for (int nXIndex = 0; nXIndex < nIMGWidth; nXIndex++)
    {
        //对图像的像素值进行规整
        unsigned char uRValue = (unsigned char)dRValue;
        unsigned char uGValue = (unsigned char)dGValue;
        unsigned char uBValue = (unsigned char)dBValue;
        //更改指定坐标处的像素值
        SetBGRPixel(theMemoryImage, nXIndex, nYIndex, nIMGWidth, nIMGHeight,uRValue,uGValue,uBValue);
        //步进指定通道图像的像素值 
        dGValue += nPixelColorAdd;
    }
}

工程示例

/***************************************************************************
*
*  本例程是一個如何操控内存图像的示例,并在章节1的基础上将过程动态的显示出来
*  2018-7-21 in Xi'an
*  by hzhy
*
*****************************************************************************/
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <iostream>
 
#pragma comment(lib,"opencv_core341d.lib")
#pragma comment(lib,"opencv_highgui341d.lib")
using namespace std;
 
/**窗口Name**/
const char* windowName = "BGR Window ...  Press ESC Quit";
 
/************************************
*
*  創建BGR內存圖像
*
************************************/
unsigned char* CreateBGRMemoryImage(int nWidth, int nHeight);
 
/************************************
*
*  窗體顯示BGR內存圖像
*
************************************/
bool ShowBGRImage(unsigned char* pImage, int nWidth, int nHeight);
 
/************************************
*
*  操控指定内存图像指定位置的像素值
*
************************************/
bool SetBGRPixel(unsigned char* pImage,int x,int y, int nWidth, int nHeight, unsigned char R, unsigned G, unsigned B);
 
 
int main(int argc, char ** argv)
{
    //设置显示窗体的size
    int nIMGWidth = 640;
    int nIMGHeight = 480;
    double nPixelColorAdd = 255.0 / nIMGWidth;
 
    //create memory image buffer
    unsigned char* theMemoryImage = CreateBGRMemoryImage(nIMGWidth, nIMGHeight);
 
    for (int nYIndex = 0; nYIndex < nIMGHeight; nYIndex++)
    {
       double dRValue = 0.0;
       double dGValue = 0.0;
       double dBValue = 0.0;
       for (int nXIndex = 0; nXIndex < nIMGWidth; nXIndex++)
       {
           unsigned char uRValue = (unsigned char)dRValue;
           unsigned char uGValue = (unsigned char)dGValue;
           unsigned char uBValue = (unsigned char)dBValue;
           SetBGRPixel(theMemoryImage, nXIndex, nYIndex, nIMGWidth, nIMGHeight,uRValue,uGValue,uBValue);
 
           dGValue += nPixelColorAdd;
       }
    }
    ShowBGRImage(theMemoryImage, nIMGWidth, nIMGHeight);
 
    cvWaitKey(0);
    delete[] theMemoryImage;
    return 0;
}
 
unsigned char* CreateBGRMemoryImage(int nWidth, int nHeight)
{
    int nImgChannel = 3;
    int nPixelIndex = 0;
    unsigned char* pMemoryImage = new unsigned char[nWidth * nHeight * nImgChannel];
 
    for (int nYIndex = 0; nYIndex < nHeight; nYIndex++)
       for (int nXIndex = 0; nXIndex < nWidth; nXIndex++)
       {
           pMemoryImage[nPixelIndex++] = 0;        // B channel
           pMemoryImage[nPixelIndex++] = 0;       // G channel
           pMemoryImage[nPixelIndex++] = 255;         // R channel
       }
 
    return pMemoryImage;
}
 
 
bool ShowBGRImage(unsigned char* pImage, int nWidth, int nHeight)
{
    IplImage* pSrcImage = cvCreateImage(cvSize(nWidth, nHeight), IPL_DEPTH_8U, 3);
    unsigned char* pImageData = (unsigned char*)pSrcImage->imageData;
    int nImageIndex = 0;
 
    //fill memory img to cvbuffer
    for (int nYIndex = 0; nYIndex < nHeight; nYIndex++)
       for (int nXIndex = 0; nXIndex < nWidth; nXIndex++)
       {
           int nCurPixelIndex = nYIndex * pSrcImage->widthStep + nXIndex * 3;
           pImageData[nCurPixelIndex++] = pImage[nImageIndex++];
           pImageData[nCurPixelIndex++] = pImage[nImageIndex++];
           pImageData[nCurPixelIndex++] = pImage[nImageIndex++];
       }
 
 
    cvShowImage(windowName, pSrcImage);
    cvReleaseImage(&pSrcImage);
    return true;
}
 
bool SetBGRPixel(unsigned char* pImage,int x,int y, int nWidth, int nHeight, unsigned char R, unsigned G, unsigned B)
{
    int nPixelIndex = (y * nWidth + x) * 3;
    pImage[nPixelIndex  ]   = B;
    pImage[nPixelIndex + 1] = G;
    pImage[nPixelIndex + 2] = R;
 
    return true;
}
 
 

效果图

求得一个红色通道的步进效果图

dRValue += nPixelColorAdd;

求得一个绿色通道的步进效果图

dGValue += nPixelColorAdd;

 

 

求得一个蓝色通道的步进效果图

dBValue += nPixelColorAdd;

 

结语:

通过本章节的学习,我们学会了如何访问内存数组,并利用一个步进公式,得到了一个过渡色的内存图像,展示了出来。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

碳纤维石头君

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

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

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

打赏作者

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

抵扣说明:

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

余额充值