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






3.50/5 (6投票s)
当 `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 版本。