图像的ASCII码显示v1—ASCII art--just for fun

3 篇文章 0 订阅
1 篇文章 0 订阅

       这两天闲着没事,觉得将图像内容用ASCII码显示出来挺有意思的,就自己尝试着写了写,到网上一搜才知道原来这东西还是一门艺术-ASCII art!!大笑

咱也跟艺术沾边了O(∩_∩)O哈哈哈~

      闲话少说,切入正题,将图像内容用ASCII码显示出来主要就是用不同的字符表示灰度,以此来区分不同的灰度值达到将内容可视化的目的,这个道理很简单,实现起来其实也不难,如果是直接输入到控制台或者txt文件的则比较简单,主要是需要设置一下字体的宽高,最好是正方形的,否则看起来会比较别扭。下面一个是将lena缩放到100*100之后在控制台窗口直接显示的截图,采用的字符是标点,字体设置的宽高相等为8*8:

        但是这种方式无法保存成图像(当然可以截图,不过那多费劲!),所以就研究了一下如何将字符直接写到图像上,这样保存图像就可以了。这时关键的问题就是如何将字符写到图像上,并且尽量让字符的宽高相等,这样看起来才不会觉得图像被挤过了⊙﹏⊙b汗!

        还是用OpenCV来将字符写到图像上,使用putText函数,不过OpenCV中的字体好像不能设置为等宽高,没办法,就取了折中的方法,将用来代替灰度的所有字符的宽度和高度取了个平均作为字符宽高,这样就将原图像中的一个像素替换为这样一个字符,而且还设置了几个选项:可以选择标点,字母或者数字来代替灰度,并且可以选择输出二值,灰度或者彩色ascii图像-----文中只使用了8个灰度级,即将整幅图像量化为了8个灰度级,这样的缺点就是对灰度分布比较集中的图像失真比较大,可以先对图像进行灰度均衡化处理之后再转换,这里没有考虑这些,下面是主要的函数代码。

char ascii_code_symbol[CODE_SIZE-7] = {'#','&','$','*','+',';','.',' ',0};
char ascii_code_letter[CODE_SIZE-7] = {'m','n','e','f','t','l','i',' ',0};
char ascii_code_number[CODE_SIZE-7] = {'8','9','5','3','2','7','1',' ',0};
char *ascii_code_8[3] = { ascii_code_symbol, ascii_code_letter, ascii_code_number};


//check the input image size and return a defined size,
// that's the max one of width and height is not bigger than 100;
cv::Size get_board_size(Mat &image)
{
	if(image.empty())
		return Size(0,0);

	int f = 0;
	float big=(float)image.rows, smal=(float)image.cols;
	if(image.cols>image.rows)
	{
		f = 1;
		big = float(image.cols);
		smal = float(image.rows);
	}
	
	cv::Size board_size;
	if(big <= 100.f)
	{
		board_size = cv::Size(image.cols, image.rows);
	}
	else
	{
		board_size = cv::Size(int(f==1?100:(100*image.cols/big)), int(f==1?(100*image.rows/big):100));
	}
	return board_size;
}

//get the char code step
int get_char_size(const string &asciiStr)
{
	//init font
	int fontFace = FONT_HERSHEY_PLAIN;
	double fontScale = 0.5;
	int thickness = 1;

	//max_size is the max of all the char code width and height,
	//or return the average size of all the char code width and height;
	int max_size = 0;
	int total_size = 0;
	for (size_t i=0; i<asciiStr.size(); ++i)
	{	
		int baseline = 0;
		string str(1, asciiStr[i]);
		cv::Size textsize = getTextSize(str, fontFace, fontScale, thickness, &baseline);
		if(max_size < textsize.height+baseline)
			max_size = textsize.height+baseline;
		if(max_size < textsize.width)
			max_size = textsize.width;
		total_size += (textsize.height+textsize.width+baseline);
	}
	return total_size/(asciiStr.size()*2);
//	return max_size;
}

/*
convert image to ascii image;
code_type: 0-symbol,1-letter,2-number
color_type: 0-binary,1-gray,2-color
*/
Mat image_to_ascii(Mat &image, int code_type, int color_type)
{
	//check input image
	if(image.empty() || code_type<0 || code_type>2 || code_type<0)
		return Mat();

	//if input is a gray image, set color_type to gray;
	if(image.channels()==1&&code_type==2)
		color_type = 1;
	
	//create the output image
	int char_size = get_char_size(ascii_code_8[code_type]);
	cv::Size board_size = get_board_size(image);
	Mat out_image(char_size*board_size.height, char_size*board_size.width, CV_8UC3,Scalar::all(0));
	
	//resize the input image to defined size;
	Mat resized_image;
	resize(image, resized_image, board_size);
	Mat gray_image;
	if(resized_image.channels() == 3)
		cvtColor(resized_image, gray_image, COLOR_BGR2GRAY);
	else
		gray_image = resized_image;

	//font init
	int fontFace = FONT_HERSHEY_PLAIN;
	double fontScale = 0.5;
	int thickness = 1;

	//print char code to the output image
	for (int i=0; i<resized_image.rows; ++i)
	{
		uchar *ptr_bgr = resized_image.ptr<uchar>(i);
		uchar *ptr_gray = gray_image.ptr<uchar>(i);
		for (int j=0; j<resized_image.cols; ++j)
		{
			//get pixel
			uchar pix_gray = ptr_gray[j];
			
			//prepare the char code and coordinate;
			cv::Point textOrg(j*char_size, (i+1)*char_size);
			string text(1, ascii_code_8[code_type][8-(pix_gray>>5)]);
			
			//colored or not
			if (color_type==0) 
			{
				putText(out_image, text, textOrg, fontFace, fontScale, Scalar::all(255));
			}
			else if(color_type==1)
			{
				putText(out_image, text, textOrg, fontFace, fontScale, Scalar::all(pix_gray));
			}
			else
			{
				putText(out_image, text, textOrg, fontFace, fontScale, Scalar(ptr_bgr[3*j],ptr_bgr[3*j+1],ptr_bgr[3*j+2]));
			}
		}
	}

	return out_image;
}


下面是采用数字的ascii字符的彩色和灰度以及二值lena图像,【对lena图像来说数字的看起来比较好,其他两种效果不如数字的】

可以看出效果还是比较好的,O(∩_∩)O,

当然这里只是简单的将像素进行了替换是基于灰度的,更高级的可以有基于结构的,如边缘,生成更加简练的内容表达,以后有时间再研究研究~~

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值