最近做的课程作业需要用到CImage函数处理图像,其中涉及到读取图像以及对图像像素进行操作,在这里记录一下自己的理解。
首先是CImage类的定义和读取图片
CImage srcImage;
CImage dstImage;
CString path = "C:\\Users\\Administrator\\Desktop\\阈值分割_20172120658\\input.png";
CString pathdown = "C:\\Users\\Administrator\\Desktop\\阈值分割_20172120658\\outtput.png";
如图 定义两个CImage类的对象,然后使用CString类型的变量定义图片的读取路径和保存路径。
srcImage.Load(path);
byte* pRealData;
这里利用CImage::Load()函数读取图片到srcImage中,接下来准备读取图像中的像素值,因为在CImage中利用堆栈进行读取的方法速度很慢,在这里我就不写了,这里使用的是直接利用c里面的指针对像素进行读取和遍历操作。首先定义一个byte类型的指针。
pRealData = (byte*)srcImage.GetBits(); //获取到图片内存点的位置
int pit = srcImage.GetPitch(); //图像每行字节数
int bitCount = srcImage.GetBPP() / 8; //获取每像素的位数~~/8得到字节数
cout << "图像每行的字节数" << pit << " " << "图像每个像素的位数" << bitCount << endl;
利用CImage::GetBits()函数获取图片内存点的位置,使用这种方法的时候,需要考虑图形的结构,使用CImage::GetBPP获取每个像素点占几位,还需要使用CImage::GetPitch获取每一行位的个数,根据GetPitch的正负值来判定GetBits获取到的head是首行的还是尾行的。负值即为尾部,正值即为头部。
其中pit得到的是字节数,也就是说如果每个像素有3个字节(RGB),一个宽为100像素的图片它的CImage::GetPitch()就是300。CImage::GetBPP()得到的是每个像素的位数,通常灰度图为8或者32,三通道RGB图像为24位。
int height = srcImage.GetHeight();
int width = srcImage.GetWidth();
cout << "height" << height << " width" << width << endl;
vector<int> gray(256);
for (int i = 1; i <= 256; i++)
{
gray.push_back(0);
}
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
gray.at((int)(*(pRealData + pit*i + j*bitCount))) += 1;
}
}
对图像的像素进行读取,需要对指针进行转换,转换为int类型。我这里是对图像的灰度值进行了统计处理。
最后附上一个利用直方图做的图像二值化
#include<atlimage.h>
#include<stdio.h>
#include<iostream>
#include<vector>
#include<opencv2\opencv.hpp>
using namespace std;
using namespace cv;
void main()
{
CImage srcImage;
CImage dstImage;
CString path = "C:\\Users\\Administrator\\Desktop\\阈值分割_20172120658\\input.png";
CString pathdown = "C:\\Users\\Administrator\\Desktop\\阈值分割_20172120658\\outtput.png";
srcImage.Load(path);
byte* pRealData;
byte* pRealData1;
byte* pRealData2;
byte* pRealData3;
pRealData = (byte*)srcImage.GetBits(); //获取到图片内存点的位置
int pit = srcImage.GetPitch(); //图像每行字节数
int bitCount = srcImage.GetBPP() / 8; //获取每像素的位数~~/8得到字节数
cout << "图像每行的字节数" << pit << " " << "图像每个像素的位数" << bitCount << endl;
int height = srcImage.GetHeight();
int width = srcImage.GetWidth();
cout << "height" << height << " width" << width << endl;
vector<int> gray(256);
for (int i = 1; i <= 256; i++)
{
gray.push_back(0);
}
//pRealData1 = pRealData;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
gray.at((int)(*(pRealData + pit*i + j*bitCount))) += 1;
}
}
int max = 0;
int sec = 0;
int locamax = 0;
int locasec = 0;
for (int i = 0; i < 256; i++)
{
cout << i << "---" << gray[i] << endl;
if (gray[i] > max)
{
max = gray[i];
locamax = i; //获取相同灰度值像素点最多的灰度值
}
}
for (int i = 0; i < 256; i++)
{
if (gray[i] > sec&&abs(i-locamax)>10) //第二多的点需要距离最多的点至少10个灰度单位
{
sec = gray[i];
locasec = i; //获取相同灰度值像素点第二多的灰度值
}
}
cout <<locamax<<"__"<<locasec << endl;
int min = (locamax + locasec) / 2; //取两峰中间值作为二值化分割阈值
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
if ((int)(*(pRealData + pit*i + j*bitCount)) < min)
{
*(pRealData + pit*i + j*bitCount) = 0;
*(pRealData + pit*i + j*bitCount+1) = 0;
*(pRealData + pit*i + j*bitCount+2) = 0;
}
else
{
*(pRealData + pit*i + j*bitCount) = 255;
*(pRealData + pit*i + j*bitCount + 1) = 255;
*(pRealData + pit*i + j*bitCount + 2) = 255;
}
}
}
srcImage.Save(pathdown);
system("pause");
}
原图
二值化