65.9K
CodeProject 正在变化。 阅读更多。
Home

一种无需使用缓慢的 GetPixel 和 SetPixel 方法即可快速处理 Windows 位图像素数据的快速方法

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.50/5 (6投票s)

2010 年 6 月 5 日

CPOL

1分钟阅读

viewsIcon

81571

downloadIcon

1127

当 `GetPixel()` 和 `SetPixel()` 速度非常慢时,尝试这个解决方案。

引言

本文展示了一种快速查看和修改像素颜色数据(Windows 位图)的方法,无需使用 `GetPixel` 和 `SetPixel` 方法。

背景

我花了好几个月的时间,因为不知道如何用 C++ 快速编辑图像(我当时使用的是 Windows API 函数 `GetPixel` 和 `SetPixel`)。我失去了一些客户。然后我花了几个星期在论坛上浏览,试图找到答案。但最终,我通过自己的努力解决了这个问题,并学习了这种简单的指针算术方法。

Using the Code

我们使用指向位图位的指针:`bitmapzor.GetBits();`。然后,我们使用指针偏移量来访问位图像素颜色数组中的另一行:`bitmapzor.GetPitch();`。

包含注释的完整代码如下所示

// FastImageManipulations.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
    //Okay Now you need a bitmap to work with. Find any bmp file on your PC and
    //Put it to C:\\1.bmp location. You can enter any name, just alter the file
    //path below:

    CImage bitmapzor;
    bitmapzor.Load(_T("C:\\1.bmp"));

    //I use ATL CImage class because it is easy to use. Low number of code lines
    //You can use HBITMAP, HGDIOBJ of GDIplus and other methods,
    //They work the same way and at the same speed, but take tons of code lines 
    //For instance you can use HBITMAP bitmapzor = (HBITMAP)ImageLoad(...)
    //And then you are to use GDI and API functions
    //Let us see the difference between standard API and pointer way:
    printf ("Now we use ATL (Api) GetPixel and SetPixel functions to " 
            "enforce (for example) all green pixels by 30%\n please " 
            "press any key to start and start counting minutes :)");

    getchar();
    COLORREF PixColor=0; //This is a color data
    int R=0,G=0,B=0; //These are the channel values

    //First we shall for instance allter all pixel colors to green using standard way
    for (int i=0; i<bitmapzor.GetWidth(); i++) //along line
        for (int j=0; j<bitmapzor.GetHeight(); j++) //new line
        {
            //This evil slow function extracts 24bit pixel color as BGR value
            PixColor = bitmapzor.GetPixel(i,j);
            R=GetRValue(PixColor);//This macro extracts red channel value
            G=GetGValue(PixColor);//This macro extracts green channel value
            B=GetBValue(PixColor);//This extracts blue pixel color
            G=(int)((float)G*1.3); //There we enforce green color by 30%.
            if (G>255) G=255; //There we ensure G is within 0-255 range
            //We can assemble the BGR 24 bit number that way
            //PixColor = B*0x10000+G*0x100+R;
            PixColor = RGB(R,G,B);//Or we can use this function
            //Now we save a new "green" pixel value back to bitmap
            bitmapzor.SetPixel(i,j,PixColor);
        }

    //Now we need to save this result to a HD:
    LPCTSTR filename=_T("C:\\GetPixel.bmp");
    //you can change the location of this file

    bitmapzor.Save(filename);
    printf ("Done, file is saved to: %s\n Please press " 
            "any key for another method demo", filename);
    getchar();

    //Okay now another way with the pointer arithmetics:
    printf ("Pointer arithmetics demo (without GetPixel and SetPixel functions): \n");
    bitmapzor.Destroy(); //Unload the changed bitmap from memory
    bitmapzor.Load("C:\\1.bmp");
    //this is a pointer to the exact bitmap pixel color array location
    BYTE* byteptr = (BYTE*)bitmapzor.GetBits();

    //You can use other functions for HBITMAP and HGDIOBJ methods to find out the 
    //container for bitmap color table.
    //For instance when you use GDI and HBITMAPS, you should use
    //BYTE* byteptr = (BYTE*)(HBITMAPINFOHEADER + HBITMAPINFOHEADER->biSize);
    //simple pointer arithmetics

    int pitch = bitmapzor.GetPitch(); //This is a pointer offset to get new line of the bitmap

    for (int i=0; i<bitmapzor.GetWidth();i++)
        for (int j=0; j<bitmapzor.GetHeight();j++)
        {
            //pointer arithmetics to find (i,j) pixel colors:
            R= *(byteptr+pitch*j+3*i);
            G= *(byteptr+pitch*j+3*i+1);
            B= *(byteptr+pitch*j+3*i+2); 

            //allter pixel G color:
            G=(int)((float)G*1.3);
            if (G>255) G=255;
            //write down the new G-Color
            *(byteptr+pitch*j+3*i+1)=G;
        }

    //Save the bitmap:
    LPCTSTR filename2 = _T("C:\\ptrarithm.bmp"); //you can use any other file name
    bitmapzor.Save(filename2);
    printf ("Done, file is saved to: %s\n Please press any key to exit program", filename2);
    getchar();
    bitmapzor.Destroy(); //destroy the bitmap
    return 0;
}

关注点

正常的位图是一个 WxH 像素表,带有头部。像素表中的每个值都是一个 24 位整数或 3x `CHAR`。要访问这些值,我们需要知道指针的起始点和偏移量。正常的位图具有负偏移量;例如,如果指向颜色表某行的指针是 `byteptr`,那么指向下一行的指针是 `byteptr-3*W`。但有时,位图是倒置的,指向下一行的指针是 `byteptr+3*W`。无论如何,偏移量(负数或正数)始终由 `GetPitch()` 方法给出。

历史

这是本文的 1.0.2 版本。

无需使用缓慢的 GetPixel 和 SetPixel 方法,在 Windows 位图像素数据上快速操作 - CodeProject - 代码之家
© . All rights reserved.