ryxcaixia 发表于 2015-5-26 11:09:43

纯C语言对BMP图像的灰度化二值化

本帖最后由 ryxcaixia 于 2015-5-26 11:14 编辑

不多说 直接贴代码动态申请释放内存引用了模板加强通用性
对bmp图像进行每个像素点的读写, 达到灰度化和二值化(很多验证码的过滤都是要进行这两部的操作)
纯指针操作, 涉及二级指针一级指针数组动态内存申请释放等, 当个语法常识看看
尤其两个申请释放二维数组内存的函数短小精悍 拿出来分享下 可作为自己的函数库
图像数据就是一个大的二维数组, 喜欢的鱼油也可以参考下印证下自己的指针功底


#include "Windows.h"
#include <stdio.h>
#include <stdlib.h>
//using namespace std;

// 这个动态申请二维内存(指针数组)的函数很有意思
template<typename T>
void NewArr(T**& Array, int row, int line)
{
      Array = new T*;
      for (int i = 0; i != row; i++)
      {
                Array = new T;
                memset(Array, 0, sizeof(T) * line);
      }
}

// 这个动态释放二维内存的函数也很有意思
template<typename T>
void DeleteArray (T**& Array, int line)
{
      for (int i = 0; i < line; i++)
      {
                delete[] Array;
                Array = NULL;
      }
      delete[] Array;
      Array = NULL;
}


// 函数说明
// path 文件图片的绝对地址
// bf, bi作为两个输出参数, 函数内部完成初始化
// lpBit, 图像数据, 一个超级大的二维数组(一级指针数组), 可以丢一个空指针进去, 函数内部代为申请内存
void ReadBitmap(const char* path, BITMAPFILEHEADER& bf, BITMAPINFOHEADER& bi, unsigned char**& lpBit)
{
      FILE* fp = fopen(path, "rb");
      if (fp == NULL)
                exit(0);

      fread(&bf, sizeof(BITMAPFILEHEADER), 1, fp); // 写入文件头
      fread(&bi, sizeof(BITMAPINFOHEADER), 1, fp); // 写入信息头

      NewArr(lpBit, bi.biHeight, (bi.biWidth * 3 + 3) / 4 * 4);
      for (int i = 0; i < bi.biHeight; i++)
                for (int j = 0; j < (bi.biWidth * 3 + 3) / 4 * 4; j++)
                        fread(&lpBit, sizeof(unsigned char), 1, fp); // 每次读入一个字节

      fclose(fp);
}

// 函数说明
// path 文件图片的绝对地址
// bf, bi作为两个输入参数,
// lpBit, 图像数据, 经过ReadBitmap初始化后作为输入参数
void WriteBitmap(const char* path, BITMAPFILEHEADER& bf, BITMAPINFOHEADER& bi, unsigned char**& lpBit, BYTE limit)
{
      FILE* fp;
      fp = fopen(path, "wb");
      if (fp == NULL)
                exit(0);

      BITMAPFILEHEADER newbf; // 初始化文件头
      memcpy(&newbf, &bf, sizeof(BITMAPFILEHEADER));
      int newbfWidth = (bi.biWidth + 3) / 4 * 4; // 4字节补齐
      int newbfImageSize = newbfWidth * bi.biHeight; // 位图数据实际大小
      newbf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
      newbf.bfSize = newbfImageSize + newbf.bfOffBits; // 位图文件实际大小

      BITMAPINFOHEADER newbi; // 初始化信息头
      memcpy(&newbi, &bi, sizeof(BITMAPINFOHEADER));
      newbi.biSizeImage = newbfImageSize;
      newbi.biBitCount = 8;

      fwrite(&newbf, sizeof(BITMAPFILEHEADER), 1, fp); // 写入文件头
      fwrite(&newbi, sizeof(BITMAPINFOHEADER), 1, fp); // 写入信息头

      RGBQUAD* pRGB = new RGBQUAD; // 初始化调色板
      for(int i = 0; i != 256; i++)
                pRGB.rgbRed = pRGB.rgbGreen = pRGB.rgbBlue = i;
      fwrite(pRGB, sizeof(RGBQUAD), 256, fp); // 写入调色板

      unsigned char** Array;
      NewArr(Array, newbi.biHeight, newbfWidth);

      for(int i = 0; i < newbi.biHeight; i++)
      {
                for(int j = 0; j < newbfWidth; j++)
                {               
                        //                        newImagedata = (ImageData + ImageData + ImageData) / 3; // 一次写入
                        Array = lpBit * 0.114 +
                              lpBit * 0.587+
                              lpBit * 0.299; // 三个依次为 B G R的颜色分量 进行灰度化
                        Array > limit ? Array = 0 : Array = 255; // 此处设置阀值
                        fwrite(&Array, sizeof(unsigned char), 1, fp); // 按每次一个字节写入
                }
      }

      DeleteArray(Array, newbi.biHeight);
      fclose(fp);
}


int main(void)
{
      BITMAPFILEHEADER bf;
      BITMAPINFOHEADER bi;
      memset(&bf, 0, sizeof(BITMAPFILEHEADER));
      memset(&bi, 0, sizeof(BITMAPINFOHEADER));
      unsigned char** lpBit = NULL;

      // 函数内部代为分配内存, 参数为二级指针, 所以函数内部动态传递出内存则形参为二级指针的引用或三级指针
      ReadBitmap("C:\\1.bmp", bf, bi, lpBit);      // 路径这里要加上"\\" 不能是单个'\'
      WriteBitmap("C:\\t1.bmp", bf, bi, lpBit, 128); // 写入的路径

      DeleteArray(lpBit, bi.biHeight);

      return 0;
}





ryxcaixia 发表于 2015-6-11 21:21:15

0 0
{:9_228:}
好的 求大腿

ap0405209 发表于 2016-11-30 17:06:34

能加个图就更好了
页: [1]
查看完整版本: 纯C语言对BMP图像的灰度化二值化