鱼C论坛

 找回密码
 立即注册
查看: 10633|回复: 3

[作品展示] 纯C语言对BMP图像的灰度化二值化

[复制链接]
发表于 2015-5-26 11:09:43 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

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

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


  1. #include "Windows.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. //using namespace std;

  5. // 这个动态申请二维内存(指针数组)的函数很有意思
  6. template<typename T>
  7. void NewArr(T**& Array, int row, int line)
  8. {
  9.         Array = new T*[row];
  10.         for (int i = 0; i != row; i++)
  11.         {
  12.                 Array[i] = new T[line];
  13.                 memset(Array[i], 0, sizeof(T) * line);
  14.         }
  15. }

  16. // 这个动态释放二维内存的函数也很有意思
  17. template<typename T>
  18. void DeleteArray (T**& Array, int line)
  19. {
  20.         for (int i = 0; i < line; i++)
  21.         {
  22.                 delete[] Array[i];
  23.                 Array[i] = NULL;
  24.         }
  25.         delete[] Array;
  26.         Array = NULL;
  27. }


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

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

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

  43.         fclose(fp);
  44. }

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

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

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

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

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

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

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

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


  88. int main(void)
  89. {
  90.         BITMAPFILEHEADER bf;
  91.         BITMAPINFOHEADER bi;
  92.         memset(&bf, 0, sizeof(BITMAPFILEHEADER));
  93.         memset(&bi, 0, sizeof(BITMAPINFOHEADER));
  94.         unsigned char** lpBit = NULL;

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

  98.         DeleteArray(lpBit, bi.biHeight);

  99.         return 0;
  100. }
复制代码





点评

我很赞同!: 5.0
我很赞同!: 5
这么热心,建议鱼友I后申请个版主~  发表于 2015-6-11 20:27
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2015-6-11 21:21:15 | 显示全部楼层
0 0

好的 求大腿
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-11-30 17:06:34 | 显示全部楼层
能加个图就更好了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-5-16 16:51

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表