案例
(空间)分辨率:726*461
宽度:726像素
高度:461像素
位深度:24
C5.1 二值图像(1位)
C5.2 灰度图像(8位)
C5.3 彩色图像(24位)
每个像素由RGB三个分量构成,取值范围是0~255
如果一个像素的R、G、B值相同,则该像素等同于灰度图像中的像素
例如:R=G=B=100,表示灰度为100的像素点
C5.4 灰度图像和彩色图像的转换
彩色图像(R,G,B)转换成灰度图像
Gray = R * 0.299 + G * 0.587 + B * 0.114
灰度图像转换成彩色图像
— 灰度图像不可能变换为原来的彩色图像
— 伪彩色处理可用于把灰度值映射成彩色的RGB值,例如在宇宙星空图片上的应用
如果atlimage.h编译报错提示不存在
COLORREF类应用
流程:
代码:
#include
#include //添加CImage类
void swap(BYTE& a, BYTE& b)//交换函数
{
BYTE temp;
temp = a;
a = b;
b = temp;
}
void redToGreen(COLORREF& c)//E1:把图像中所有红色的点改成绿色
{
//获取c中RGB的值
BYTE r = GetRValue(c);//获取c中R的值
BYTE g = GetGValue(c);//获取c中G的值
BYTE b = GetBValue(c);//获取c中B的值
//如果红色分量更大,则与绿色交换
if (r > g && r > b)
{
swap(r, g);//调用交换函数
}
c = RGB(r, g, b);//c中存储交换后的rgb值
}
int main()
{
//1 读取与保存图像路径
LPCTSTR srcFilePath = _T("1a.jpg");//源图像路径
LPCTSTR destFilePath = _T("1b.jpg");//目标图像路径
//2 加载图像
CImage srcImage;//新建一个CImage类对象
srcImage.Load(srcFilePath);//从源图像路径中加载图像
//3 获取图像的高和宽
int width, high;
width = srcImage.GetWidth();//获取图像的宽度
high = srcImage.GetHeight();//获取图像的高度
//4 遍历整个图像的像素点,获取整个图像
for (int x = 0; x < width; x++)//遍历x轴
{
for (int y = 0; y < high; y++)//遍历y轴
{
COLORREF c = srcImage.GetPixel(x, y);//新建一个COLORREF类对象,用来存储得到的图像像素点颜色
redToGreen(c);//调用E1函数,处理颜色
srcImage.SetPixel(x, y, c);//设置图像像素点的颜色
}
}
//6 保存图像到指定路径
srcImage.Save(destFilePath);
return 0;
}
流程
代码:
#include
#include
void colorToGray(COLORREF& c)//E2:把彩色图像修改成灰度图像
{
BYTE r = GetRValue(c);
BYTE g = GetGValue(c);
BYTE b = GetBValue(c);
BYTE gray = r * 0.299 + g * 0.587 + b * 0.114;//彩色转灰度图像公式
c = RGB(gray, gray, gray);//c中存储转换后的灰度值
}
int main()
{
LPCTSTR srcFilePath = _T("1a.jpg");
LPCTSTR destFilePath = _T("3c.jpg");
CImage srcImage;
srcImage.Load(srcFilePath);
int width, high;
width = srcImage.GetWidth();
high = srcImage.GetHeight();
for (int x = 0; x < width; x++)
{
for (int y = 0; y < high; y++)
{
COLORREF c = srcImage.GetPixel(x, y);
colorToGray(c);//调用E2函数,处理颜色
srcImage.SetPixel(x, y, c);
}
}
srcImage.Save(destFilePath);
return 0;
}
流程:
代码:
#include
#include
void invertColor(COLORREF& c)//E3:反色
{
BYTE r = GetRValue(c);
BYTE g = GetGValue(c);
BYTE b = GetBValue(c);
c = RGB(255 - r, 255 - g, 255 - b);//对该像素点的rgb值进行反色处理
}
int main()
{
LPCTSTR srcFilePath = _T("1a.jpg");
LPCTSTR destFilePath = _T("4d.jpg");
CImage srcImage;
srcImage.Load(srcFilePath);
int width, high;
width = srcImage.GetWidth();
high = srcImage.GetHeight();
for (int x = 0; x < width; x++)
{
for (int y = 0; y < high; y++)
{
COLORREF c = srcImage.GetPixel(x, y);
invertColor(c);//调用E3函数,处理颜色
srcImage.SetPixel(x, y, c);
}
}
srcImage.Save(destFilePath);
return 0;
}
流程:
代码:
#include
#include
int main()
{
LPCTSTR srcFilePath = _T("11a.jpg");
LPCTSTR destFilePath = _T("22b.jpg");
CImage srcImage;//创建源图像的对象
CImage srcImage2;//创建目标图像的对象
srcImage.Load(srcFilePath);//加载srcImage的源图像
srcImage2.Load(srcFilePath);//加载srcImage2的源图像
int width, high;
width = srcImage.GetWidth();
high = srcImage.GetHeight();
for (int x = 0; x < width; x++)
{
for (int y = 0; y < high; y++)
{
COLORREF c = srcImage.GetPixel(x, y);//从源图像中获取像素点的颜色
srcImage2.SetPixel(width - x - 1, y, c);//从x负方向设置目标图像的像素点的颜色
}
}
srcImage2.Save(destFilePath);//保存目标图像
return 0;
}
方法二
分析:
流程:
代码:
#include
#include
int main()
{
LPCTSTR srcFilePath = _T("11a.jpg");
LPCTSTR destFilePath = _T("222b.jpg");
CImage srcImage;
srcImage.Load(srcFilePath);
int width, high;
width = srcImage.GetWidth();
high = srcImage.GetHeight();
for (int x = 0; x < width / 2; x++)//除以2,互换一半即可,若不除以2会导致又重新互换回去
{
for (int y = 0; y < high; y++)//高度不变,高度需一直遍历
{
COLORREF c = srcImage.GetPixel(x, y);//从源图像中获取像素点的颜色
COLORREF c1 = srcImage.GetPixel(width - x - 1, y);//创建一个新COLORREF对象,用于从源图像x轴最右端获取指定坐标像素点的颜色
srcImage.SetPixel(x, y, c1);//将x轴左边图像像素点的颜色换成x轴右边图像像素点的颜色
srcImage.SetPixel(width - x - 1, y, c);//将x轴右边图像像素点的颜色换成x轴左边图像像素点的颜色
}
}
srcImage.Save(destFilePath);
return 0;
}
CImage类快速读写常用方法
int bpp = img.GetBPP();
int pitch = img.GetPitch();
BYTE *pData = (BYTE *)img.GetBits();
BYTE b = *(pData + y * pitch + x * bpp / 8 + 0);
BYTE g = *(pData + y * pitch + x * bpp / 8 + 1);
BYTE r = *(pData + y * pitch + x * bpp / 8 + 2);
流程:
代码:
#include
#include
int main()
{
//1 获取和设置图像
LPCTSTR srcFilePath = _T("3.jpg");
LPCTSTR destFilePath = _T("3c.jpg");
//2 加载图像
CImage srcImage;
srcImage.Load(srcFilePath);
//3 获取图像的宽度和高度
int width, high;
width = srcImage.GetWidth();
high = srcImage.GetHeight();
//4 得到位深度和一行字节数
int bpp = srcImage.GetBPP();//获取图像像素点的位数;bpp / 8 获取像素点的字节数
int pitch = srcImage.GetPitch();//获取一行的字节数
//5 获取首字节地址
BYTE* pData = (BYTE*)srcImage.GetBits();//获取图像首字节的地址
//6 遍历图像
for (int x = 0; x < width; x++)
{
for (int y = 0; y < high; y++)
{
//通过指针访问图像(x,y)坐标像素点的颜色RGB值,相邻两个像素点之间相差3个字节
BYTE b = *(pData + y * pitch + x * bpp / 8 + 0);//指针访问像素点颜色的B值
BYTE g = *(pData + y * pitch + x * bpp / 8 + 1);//指针访问像素点颜色的G值
BYTE r = *(pData + y * pitch + x * bpp / 8 + 2);//指针访问像素点颜色的R值
BYTE gray = r * 0.299 + g * 0.587 + b * 0.114;//彩色转灰度图像公式
//对指针指向的值进行赋值,从而改变源图像
*(pData + y * pitch + x * bpp / 8 + 0) = gray;
*(pData + y * pitch + x * bpp / 8 + 1) = gray;
*(pData + y * pitch + x * bpp / 8 + 2) = gray;
}
}
srcImage.Save(destFilePath);
return 0;
}
图像缩放的步骤:
代码:
#include
#include
void getBGR(int x, int y, int bpp, int pitch, BYTE* pData)//获取图像像素点颜色的函数
{
BYTE b = *(pData + y * pitch + x * bpp / 8 + 0);
BYTE g = *(pData + y * pitch + x * bpp / 8 + 1);
BYTE p = *(pData + y * pitch + x * bpp / 8 + 2);
}
int main()
{
LPCTSTR srcFilePath = _T("3.jpg");
LPCTSTR destFilePath = _T("4.jpg");
CImage srcImage;//创建源图像
CImage destImage;//创建目标图像
srcImage.Load(srcFilePath);
int width, high;
width = srcImage.GetWidth();
high = srcImage.GetHeight();
int bpp, pitch;
bpp = srcImage.GetBPP();
pitch = srcImage.GetPitch();
BYTE* pData = (BYTE*)srcImage.GetBits();
//1 调用Create函数创建一张缩放后尺寸的新图
destImage.Create(width / 2, high / 2, bpp);//宽度,高度,位深度;创建的目标图片的大小和位深度
//2 调用SetStretchBltMode函数设置清晰的缩放模式
SetStretchBltMode(destImage.GetDC(), COLORONCOLOR);//COLORONCOLOR——清晰模式;GetDC()——关联srcImage和destImage两个图像的数据
destImage.ReleaseDC();//释放一下(因为有GetDC)
//3 调用Draw函数或者StretchBlt函数把源图Src的数据缩放写入新图Dest中
srcImage.Draw(destImage.GetDC(), 0, 0, width / 2, high / 2);//填充数据:目标图像的填充位置与大小
destImage.ReleaseDC();//释放一下(因为有GetDC)
//4 调用Save函数保存图片
destImage.Save(destFilePath);
return 0;
}
注意事项:
图像截取的步骤:
代码:
#include
#include
void getBGR(int x, int y, int bpp, int pitch, BYTE* pData)
{
BYTE b = *(pData + y * pitch + x * bpp / 8 + 0);
BYTE g = *(pData + y * pitch + x * bpp / 8 + 1);
BYTE p = *(pData + y * pitch + x * bpp / 8 + 2);
}
int main()
{
LPCTSTR srcFilePath = _T("3.jpg");
LPCTSTR destFilePath = _T("5.jpg");
CImage srcImage;
CImage destImage;
srcImage.Load(srcFilePath);
int width, high;
width = srcImage.GetWidth();
high = srcImage.GetHeight();
int bpp, pitch;
bpp = srcImage.GetBPP();
//1 调用Create函数创建一张新图
destImage.Create(width / 2, high / 2, bpp);
//2 调用Draw函数把源图src的部分数据写入新图dest中
srcImage.Draw(destImage.GetDC(), 0, 0, width / 2, high / 2, width / 4, high / 8, width / 2, high / 2);
//前四个参数表示:填充到目标图像的哪个位置以及填充的大小;后四个参数表示:从源图像哪个位置开始截取以及截取的大小
destImage.ReleaseDC();
//3 调用Save函数保存图片
destImage.Save(destFilePath);
return 0;
}
图片拼接的步骤:
代码:
#include
#include
void getBGR(int x, int y, int bpp, int pitch, BYTE* pData)
{
BYTE b = *(pData + y * pitch + x * bpp / 8 + 0);
BYTE g = *(pData + y * pitch + x * bpp / 8 + 1);
BYTE p = *(pData + y * pitch + x * bpp / 8 + 2);
}
int main()
{
LPCTSTR srcFilePath = _T("5.jpg");
LPCTSTR destFilePath = _T("6.jpg");
CImage srcImage;
CImage destImage;
srcImage.Load(srcFilePath);
int width, high;
width = srcImage.GetWidth();
high = srcImage.GetHeight();
int bpp, pitch;
bpp = srcImage.GetBPP();
//1 调用Create函数创建一张新图
destImage.Create(width * 2, high, bpp);
//2 调用Draw函数把源图src的部分数据写入新图dest中
srcImage.Draw(destImage.GetDC(), 0, 0, width, high, 0, 0, width, high);//第一次截取并填充了左半部分
destImage.ReleaseDC();
srcImage.Draw(destImage.GetDC(), width, 0, width, high, 0, 0, width, high);//第二次截取并填充了右半部分,填充起始点发生变化
destImage.ReleaseDC();
//3 调用Save函数保存图片
destImage.Save(destFilePath);
return 0;
}
把图片变成m行n列的图,要求彩色图像和灰度图像间隔。m和n由键盘输入。例如当m=4,n=5时:
方法一
分析:
流程:
代码:
#include
#include
void colorToGray(int x, int y, int bpp, int pitch, BYTE* pData)
{
BYTE b = *(pData + y * pitch + x * bpp / 8 + 0);
BYTE g = *(pData + y * pitch + x * bpp / 8 + 1);
BYTE r = *(pData + y * pitch + x * bpp / 8 + 2);
BYTE gray = r * 0.299 + g * 0.587 + b * 0.114;
*(pData + y * pitch + x * bpp / 8 + 0) = gray;
*(pData + y * pitch + x * bpp / 8 + 1) = gray;
*(pData + y * pitch + x * bpp / 8 + 2) = gray;
}
void traversal(int width, int high, int bpp, int pitch, BYTE* pData)
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < high; y++)
{
colorToGray(x, y, bpp, pitch, pData);
}
}
}
int main()
{
LPCTSTR srcFilePath = _T("5.jpg");
LPCTSTR destFilePath = _T("5c.jpg");
CImage srcImage, srcImage2;
CImage destImage;
srcImage.Load(srcFilePath);
srcImage2.Load(srcFilePath);
int width, high;
width = srcImage.GetWidth();
high = srcImage.GetHeight();
int bpp, pitch;
bpp = srcImage.GetBPP();
pitch = srcImage.GetPitch();
BYTE* pData = (BYTE*)srcImage.GetBits();
int m, n; std::cin >> m >> n;
destImage.Create(width, high, bpp);
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (n % 2 != 0)//若总列数是奇数
{
if (j % 2 != 0 && i % 2 == 0)//若列数是奇数且行数为偶数,则位灰度图
{
traversal(width, high, bpp, pitch, pData);
srcImage.Draw(destImage.GetDC(), (j * width) / n, (i * high) / m, width / n, high / m, 0, 0, width, high);
destImage.ReleaseDC();
}
else if (j % 2 == 0 && i % 2 != 0)//若列数为偶数且行数为奇数,则为灰度图
{
traversal(width, high, bpp, pitch, pData);
srcImage.Draw(destImage.GetDC(), (j * width) / n, (i * high) / m, width / n, high / m, 0, 0, width, high);
destImage.ReleaseDC();
}
else//其他均为彩色图
{
srcImage2.Draw(destImage.GetDC(), (j * width) / n, (i * high) / m, width / n, high / m, 0, 0, width, high);
destImage.ReleaseDC();
}
}
else//若总列数是偶数
{
if (j % 2 != 0)//若列数是奇数
{
traversal(width, high, bpp, pitch, pData);
srcImage.Draw(destImage.GetDC(), (j * width) / n, (i * high) / m, width / n, high / m, 0, 0, width, high);
destImage.ReleaseDC();
}
else//若列数是偶数
{
srcImage2.Draw(destImage.GetDC(), (j * width) / n, (i * high) / m, width / n, high / m, 0, 0, width, high);
destImage.ReleaseDC();
}
}
}
}
destImage.Save(destFilePath);
return 0;
}
方法二
分析:
流程:
代码:
#include
#include
int main()
{
//获取和设置保存源图片和目标图像的路径
LPCTSTR srcFilePath = _T("5.jpg");
LPCTSTR destFilePath = _T("123.jpg");
//创建类对象,源图像对象,灰度图对象,目标图像对象;加载源图像和灰度图
CImage srcImage, grayImage, destImage;
srcImage.Load(srcFilePath);
grayImage.Load(srcFilePath);
//获取宽度、高度、位深度、一行字节数、首字节地址
int width = grayImage.GetWidth();
int high = grayImage.GetHeight();
int bpp = grayImage.GetBPP();
int pitch = grayImage.GetPitch();
BYTE* pData = (BYTE*)grayImage.GetBits();
//输入m行n列
int m, n; std::cin >> m >> n;
//将彩色图变为灰度图
for (int x = 0; x < width; x++)
{
for (int y = 0; y < high; y++)
{
BYTE b = *(pData + y * pitch + x * bpp / 8 + 0);
BYTE g = *(pData + y * pitch + x * bpp / 8 + 1);
BYTE r = *(pData + y * pitch + x * bpp / 8 + 2);
int gray = r * 0.299 + g * 0.587 + b * 0.114;
*(pData + y * pitch + x * bpp / 8 + 0) = gray;
*(pData + y * pitch + x * bpp / 8 + 1) = gray;
*(pData + y * pitch + x * bpp / 8 + 2) = gray;
}
}
//创建一个“存放”目标图像的新窗口
destImage.Create(n * width, m * high, bpp);
按照输入的行和列遍历每个目标图像的位置
for (int x = 0; x < m; x++)//行
{
for (int y = 0; y < n; y++)//列
{
if ((x + y) % 2 == 0)//如果“行+列”的坐标为偶数,绘制源图
{
srcImage.Draw(destImage.GetDC(), y * width, x * high, width, high, 0, 0, width, high);//从源图像中获取彩色像素点
destImage.ReleaseDC();//释放
}
else//如果“行+列”的坐标为奇数,绘制灰度图
{
grayImage.Draw(destImage.GetDC(), y * width, x * high, width, high, 0, 0, width, high);//从灰度图中获取彩色像素点
destImage.ReleaseDC();
}
}
}
destImage.Save(destFilePath);//保存目标图像到指定路径
return 0;
}
流程:
代码:
#include
#include
int main()
{
//读取和保存源图像和目标图像路径
LPCTSTR srcFilePath = _T("5.jpg");
LPCTSTR destFilePath = _T("56.jpg");
//创建CImage类对象及加载图像
CImage srcImage, destImage;
srcImage.Load(srcFilePath);
//获取图像的宽度、高度及位深度
int width, high, bpp;
width = srcImage.GetWidth();
high = srcImage.GetHeight();
bpp = srcImage.GetBPP();
//创建一个目标图像窗口
destImage.Create(5000, 5000, bpp);//创建一个分辨率为5000*5000的窗口
//遍历图像
for (int x = 0; x <= ceil(5000 / width); x++)//ceil()——取整函数
{
for (int y = 0; y <= ceil(5000 / high) + 1; y++)
{
srcImage.Draw(destImage.GetDC(), width * x, high * y, width, high, 0, 0, width, high);//目标图像的绘制位置随x,y(已填充个数)的变化而变化
destImage.ReleaseDC();
}
}
destImage.Save(destFilePath);
return 0;
}
步骤:
代码:
#include
#include
void colorChange(int width, int high, int bpp, int pitch, BYTE* pData)//变色函数
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < high; y++)
{
//获取每个坐标像素点的颜色
BYTE b = *(pData + y * pitch + x * bpp / 8 + 0);
BYTE g = *(pData + y * pitch + x * bpp / 8 + 1);
BYTE r = *(pData + y * pitch + x * bpp / 8 + 2);
if (r > g && r > b)//偏红的像素点
{
//R值和B值交换
*(pData + y * pitch + x * bpp / 8 + 0) = r;
*(pData + y * pitch + x * bpp / 8 + 1) = g;
*(pData + y * pitch + x * bpp / 8 + 2) = b;
}
}
}
}
int main()
{
LPCTSTR srcFilePath = _T("Flower.jpg");
LPCTSTR destFilePath = _T("Flower2.jpg");
CImage srcImage;
srcImage.Load(srcFilePath);
int width, high;
width = srcImage.GetWidth();
high = srcImage.GetHeight();
int bpp, pitch;
bpp = srcImage.GetBPP();
pitch = srcImage.GetPitch();
BYTE* PData = (BYTE*)srcImage.GetBits();
colorChange(width, high, bpp, pitch, PData);
srcImage.Save(destFilePath);
return 0;
}
函数声明:
HSV RGB2HSV(COLORREF c)
函数功能:
把COLORREF类对象c的颜色信息转换成一个HSV类对象返回。
代码:
#include
#include
#include
#include
//RGB->HSV
class HSV//HSV类
{
public:
double H, S, V;//定义成员变量
HSV() {}//无参构造函数
HSV(double h, double s, double v) :H(h), S(s), V(v) {}//有参构造函数且初始化
};
HSV RGB2HSV(COLORREF c)//RGB至HSV转换函数
{
//从COLORREF类对象c中获取颜色RGB值
BYTE R = GetRValue(c);
BYTE G = GetGValue(c);
BYTE B = GetBValue(c);
double H, S, V;
//转换公式
R = R / 255, G = G / 255, B = B / 255;
V = max(R, G, B);
if (V != 0)
{
S = (V - min(R, G, B)) / V;
if (V = R)
{
H = (60 * (G - B)) / V - min(R, G, B);
if (H < 0)
{
H = H + 360;
return HSV(H, S, V);
}
return HSV(H, S, V);
}
if (V = G)
{
H = 120 + ((60 * (B - R)) / (V - min(R, G, B)));
if (H < 0)
{
H = H + 360;
return HSV(H, S, V);
}
return HSV(H, S, V);
}
if (V = B)
{
H = 240 + ((60 * (R - G)) / (V - min(R, G, B)));
if (H < 0)
{
H = H + 360;
return HSV(H, S, V);
}
return HSV(H, S, V);
}
}
else//V = 0,此时RGB均为0
{
S = 0;
H = 0;
return HSV(H, S, V);
}
}
函数声明:
COLORREF HSV2RGB(HSV hsv)
函数功能:
把HSV类对象hsv的颜色信息转换成一个COLORREF类对象返回。
代码:
//HSV->RGB
COLORREF HSV2RGB(HSV hsv)
{
//定义变量
BYTE R, G, B;
double H, S, V;
H = hsv.H;
S = hsv.S;
V = hsv.V;
//转换公式
double C, X, m;
C = V * S;
X = C * (1 - (abs(((int)H / 60) % 2 - 1)));
m = V - C;
if (H >= 0 && H < 60)
{
R = C;
G = X;
B = 0;
R = (R + m) * 255;
G = (G + m) * 255;
B = (B + m) * 255;
//返回COLORREF类型的值
COLORREF c;
c = RGB(R, G, B);
return c;
}
if (H >= 60 && H < 120)
{
R = X;
G = C;
B = 0;
R = (R + m) * 255;
G = (G + m) * 255;
B = (B + m) * 255;
//返回COLORREF类型的值
COLORREF c;
c = RGB(R, G, B);
return c;
}
if (H >= 120 && H < 180)
{
R = 0;
G = C;
B = X;
R = (R + m) * 255;
G = (G + m) * 255;
B = (B + m) * 255;
//返回COLORREF类型的值
COLORREF c;
c = RGB(R, G, B);
return c;
}
if (H >= 180 && H < 240)
{
R = 0;
G = X;
B = C;
R = (R + m) * 255;
G = (G + m) * 255;
B = (B + m) * 255;
//返回COLORREF类型的值
COLORREF c;
c = RGB(R, G, B);
return c;
}
if (H >= 240 && H < 300)
{
R = X;
G = 0;
B = C;
R = (R + m) * 255;
G = (G + m) * 255;
B = (B + m) * 255;
//返回COLORREF类型的值
COLORREF c;
c = RGB(R, G, B);
return c;
}
if (H >= 300 && H < 360)
{
R = C;
G = 0;
B = X;
R = (R + m) * 255;
G = (G + m) * 255;
B = (B + m) * 255;
//返回COLORREF类型的值
COLORREF c;
c = RGB(R, G, B);
return c;
}
}
/*
提取信息:HSV——对象名.成员函数
RGB——GetRVaule(对象名)
*/