图像灰度化和二值化在图像识别里面经常使用,这里以HLS实现整个过程
一、实现功能:
读取一张bmp图片,输出一张灰度化bmp图片和二值化后的黑白图片
二、需要用到的接口
1、读写图片工具函数bmp_tools.cpp
这里我们用现成的
2、输入输出流接口传递像素点
三、思路
整体写两个模块,
1.一个用于彩色图片灰度化,
2.另一个用于灰度化图片二值化
然后编写主函数去读取图片通过流接口传入传出并写出图片显示
主函数流程
1、读取图片
2、将一维数组的像素点写到in_img_s流里面
3、灰度化处理 公式 gray = 0.299r + 0.578g +
4、二值化处理 输入为阈值 输入流 输出流 行 列 ;公式 ·y = gray > x ? 255 : 0
5、从输出流里面把像素点读取到一维数组
6、把一维数组的像素点写进图片
7、释放内存
灰度化流程
1、将输入流里面的像素点读取出来 到
2、把predata的r g b拆分出来,拆分成4个字节
3、代入计算公式,计算灰度值gray = 0.299r + 0.578g + 0.114b
4、把灰度值分别放到r、g、b
5、设定上限,限制到255
6、将r 、g、b合并成unsigned int 像素点
7、将像素点写进输出流
二值化流程
1、将输入流里面的像素点读取出来 到
2、代入公式 y = gray > x ? 255 : 0
3、生成 unsigned int 像素点
4、将像素点写进输出流
四、编写代码
main.cpp
#include <stdio.h>
#include <stdlib.h>
#include "HLS/hls.h"
#include "bmp_tools.h"
#include "gray.h"
#include "banary.h"
unsigned int *img_in;
unsigned int *img_out1;
unsigned int *img_out2;
int rows,cols;
std::string input_bmp_filename = "*.bmp";
std::string output1_bmp_filename = "gray.bmp";
std::string output2_bmp_filename = "banary.bmp";
//typedef ihc::stream_in<unsigned int> input_image_stream;
//typedef ihc::stream_out<unsigned int> output_image_stream;
int main()
{
input_image_stream in_img_s;
output_image_stream out1_img_s;
output_image_stream out2_img_s;
//一、读取图片
read_bmp (input_bmp_filename.c_str(), &img_in, rows, cols);
printf("1\n");
//二、将一维数组的像素点写到in_img_s流里面
for(int i = 0; i < (rows*cols); i++)
{
in_img_s.write(img_in[i]);
}
printf("2\n");
//三、灰度化处理 公式 gray = 0.299r + 0.578g + 0.114b
gray_deal(in_img_s, out1_img_s, rows, cols);
printf("3\n");
img_out1 = (unsigned int *)malloc(rows*cols*sizeof(unsigned int));
for(int j = 0; j < (rows*cols); j++)
{
img_out1[j] = out1_img_s.read();
}
for(int j = 0; j < (rows*cols); j++)
{
out1_img_s.write(img_out1[j]);
}
//四、二值化处理 输入为阈值 输入流 输出流 行 列 ;公式 ·y = gray > x ? 255 : 0
banary_deal(out1_img_s, out2_img_s, rows, cols);
printf("4\n");
//五、从输出流里面把像素点读取到一维数组
img_out2 = (unsigned int *)malloc(rows*cols*sizeof(unsigned int));
for(int k = 0; k < (rows*cols); k++)
{
img_out2[k] = out2_img_s.read();
}
printf("5\n");
//六、把一维数组的像素点写进图片
write_bmp (output1_bmp_filename.c_str(), img_out1, rows, cols);
write_bmp (output2_bmp_filename.c_str(), img_out2, rows, cols);
printf("6\n");
//七、释放内存
free(img_in);
free(img_out1);
free(img_out2);
printf("7\n");
return 0;
}
gray.cpp
#include "HLS/hls.h"
#include <stdio.h>
#include <stdlib.h>
#include "gray.h"
component void gray_deal(input_image_stream &input, output_image_stream &out, int rows, int cols)
{
unsigned char rgb[4];
unsigned char gray_tmp;
#pragma unroll
for(int i = 0; i < (rows * cols); i++)
{
//1、将输入流里面的像素点读取出来 到predata
unsigned int img_date = input.read();
//2、把predata的r g b拆分出来,拆分成4个字节
rgb[0] = img_date & 0xff;//蓝色字节
rgb[1] = (img_date >> 8) & 0xff;//绿色字节
rgb[2] = (img_date >> 16) & 0xff;//红色字节
rgb[3] = 0;
//3、代入计算公式,计算灰度值gray = 0.299r + 0.578g + 0.114b
gray_tmp = 0.299*rgb[2] + 0.578*rgb[1] + 0.114*rgb[0];
//4、把灰度值分别放到r、g、b
rgb[0] = gray_tmp;
rgb[1] = gray_tmp;
rgb[2] = gray_tmp;
//5、设定上限,限制到255
//--
//6、将r 、g、b合并成unsigned int 像素点
img_date = 0;
img_date = ((unsigned int )rgb[2] << 16);
img_date = img_date | ((unsigned int )rgb[1] << 8);
img_date = img_date | rgb[0];
//7、将像素点写进输出流
out.write(img_date);
}
}
gray.h
#ifndef __GRAY_H
#define __GRAY_H
typedef ihc::stream_in<unsigned int> input_image_stream;
typedef ihc::stream_out<unsigned int> output_image_stream;
component void gray_deal(input_image_stream &input, output_image_stream &out, int rows, int cols);
#endif
banary.cpp
#include "HLS/hls.h"
#include <stdio.h>
#include <stdlib.h>
#include "banary.h"
#define XX 150
component void banary_deal(output_image_stream &gray, output_image_stream &b_out, int rows, int cols)
{
for(int i = 0; i < (rows * cols); i++)
{
//1、将输入流里面的像素点读取出来 到predata 灰度值
unsigned int img_data = gray.read();
unsigned char tmp = img_data & 0xff;
unsigned char banary = 0;
//2、代入公式 y = gray > x ? 255 : 0
banary = tmp > XX ? 255 : 0;
//3、生成 unsigned int 像素点
img_data = 0;
img_data = banary;//蓝色部分
img_data = img_data | ((unsigned int )banary << 8);//绿色部分
img_data = img_data | ((unsigned int )banary << 16);//红色部分
//4、将像素点写进输出流
b_out.write(img_data);
}
}
banary.h
#ifndef __BANARY_H
#define __BANARY_H
typedef ihc::stream_in<unsigned int> input_image_stream;
typedef ihc::stream_out<unsigned int> output_image_stream;
component void banary_deal(output_image_stream &gray, output_image_stream &b_out, int rows, int cols);
#endif
bmp_tools.cpp
// bmp_tools.cpp
#include "bmp_tools.h"
#include <stdio.h>
#include <stdlib.h>
// Bitmap header size in bytes
static const int BMP_HEADER_SIZE = 54;
void read_bmp (const char* filename, unsigned int** img_data, int& height, int& width) {
FILE *fp;
if ((fp=fopen(filename,"rb"))==NULL) {
printf("can't open file %s for binary reading\n", filename);
exit(1);
}
// Skip over unimportant parts of header
for (int i=0; i<18; i++) fgetc(fp);
//read width and height
fread(&width, sizeof(int), 1, fp);
fread(&height, sizeof(int), 1, fp);
if (height < 0 || width < 0) {
printf("error got height %d, width %d\n", height, width);
exit(1);
}
printf("image size is %d (width) by %d (height) pixels\n", width, height);
*img_data = (unsigned int*) malloc(width * height * sizeof(unsigned int));
// Skip remaining part of header
for (int i=0; i<28; i++) fgetc(fp);
// BMP: Each line must be a multiple of 4 bytes
int padding = (4-((width*3)&3))&3;
int idx=0;
// Color order is BGR, read across bottom row, then repeat going up rows
for (int i=0; i< height; ++i) {
for (int j=0; j< width; ++j) {
unsigned char b = fgetc(fp); //B
unsigned char g = fgetc(fp); //G
unsigned char r = fgetc(fp); //R
(*img_data)[idx] = (((unsigned int ) r << 16) | ((unsigned int ) g << 8) | ((unsigned int ) b << 0));
idx++;
}
// Discard the padding bytes
for (int j=0; j< padding; ++j) {
unsigned char b = fgetc(fp);
}
}
fclose(fp);
}
void write_bmp (const char* filename, unsigned int* img_data, int& height, int& width) {
FILE *fp;
unsigned int file_size = width * height * 3 + BMP_HEADER_SIZE;
unsigned char header[BMP_HEADER_SIZE] = { 0x42, 0x4d, // BMP & DIB
(file_size & 0xff), ((file_size >> 8) & 0xff), ((file_size >> 16) & 0xff), ((file_size >> 24) & 0xff), // size of file in bytes
0x00, 0x00, 0x00, 0x00, // reserved
0x36, 0x00, 0x00, 0x00, // offset of start of image data
0x28, 0x00, 0x00, 0x00, // size of the DIB header
(width & 0xff), ((width >> 8) & 0xff), ((width >> 16) & 0xff), ((width >> 24) & 0xff), // width in pixels
(height & 0xff), ((height >> 8) & 0xff), ((height >> 16) & 0xff), ((height >> 24) & 0xff), // height in pixels
0x01, 0x00, // number of color planes
0x18, 0x00, // number of bits per pixel
0x00, 0x00, 0x00, 0x00, // no compression - BI_RGB
0x00, 0x00, 0x00, 0x00, // image size - dummy 0 for BI_RGB
0x13, 0x0b, 0x00, 0x00, // horizontal ppm
0x13, 0x0b, 0x00, 0x00, // vertical ppm
0x00, 0x00, 0x00, 0x00, // default 2^n colors in palatte
0x00, 0x00, 0x00, 0x00 // every color is important
};
// Open file for write
if ((fp=fopen(filename,"wb"))==NULL) {
printf("can't open file %s for binary writing\n", filename);
exit(1);
}
// Write header
fwrite(header, 1, BMP_HEADER_SIZE, fp);
// Write data: Line size must be a multiple of 4 bytes
int padding = (4-((width*3)&3))&3;
int idx = 0;
for (int i = 0; i < height; ++i) {
unsigned char p[3];
for (int j = 0; j < width ; ++j) {
// written in B, G, R order
p[0] = (img_data[idx] >> 0) & 0xff; //B
p[1] = (img_data[idx] >> 8) & 0xff; //G
p[2] = (img_data[idx] >> 16) & 0xff; //R
idx++;
fwrite(p, 1, 3, fp);
}
// Pad to multiple of 4 bytes
if (padding) {
p[0]=p[1]=p[2]=0;
fwrite(p,1,padding,fp);
}
}
fclose(fp);
}
bmp_tools.h
// bmp_tools.h
#ifndef BMP_TOOLS_H
#define BMP_TOOLS_H
void read_bmp (const char* filename, unsigned int** img_data, int& height, int& width);
void write_bmp (const char* filename, unsigned int* img_data, int& height, int& width);
#endif // BMP_TOOLS_H
五、编译
i++ -march=x86-64 -o img main.cpp bmp_tool.cpp gray.cpp banary.cpp
六、运行测试
首先需要添加输入图片的名字,注意必须是24位深度的bmp图片
输入img.exe
然后打开看生成的图片
这里是我这里的结果
原图
灰度化
二值化