HLS——图像灰度化和二值化处理示例

图像灰度化和二值化在图像识别里面经常使用,这里以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

六、运行测试
HLS——图像灰度化和二值化处理示例
首先需要添加输入图片的名字,注意必须是24位深度的bmp图片
输入img.exe
然后打开看生成的图片
这里是我这里的结果
原图
HLS——图像灰度化和二值化处理示例
灰度化
HLS——图像灰度化和二值化处理示例
二值化
HLS——图像灰度化和二值化处理示例

上一篇:基于SPI接口的OLED数据显示


下一篇:树莓派3B+连接DLPDLCR2000EVM