热敏打印机是一种在打印头上安装有半导体加热元件,打印头加热并接触热敏打印纸后就可以打印出需要的图案的便携式打印机,其原理与热敏式传真机类似,图像是通过加热,在膜中产生化学反应而生成的,常温下可保存长达几年之久。热敏打印具有速度快、噪音低,使用方便的优点,但是热敏打印机打印的是黑白图片,且打印的像素宽度有限,在打印一些内容复杂的图像时效果并不理想,需要对图像进行前期的算法处理。

Floyd-Steinberg Dithering

Floyd-Steinberg Dithering 是一种抖动的误差扩散法,它将一个像素点的量化误差传递到相邻的像素。如下矩阵,用星号(*)表示的像素表示当前正在扫描的像素,并且空白像素是先前扫描的像素。该算法从左到右,从上到下扫描图像,逐个量化像素值。每次量化误差被传送到相邻像素,同时不影响已经量化的像素。因此,如果向下舍入多个像素,则下一个像素向上舍入的可能性更大,使得平均来说量化误差接近于零。
在这里插入图片描述
最简单的理解就是将上述矩阵理解成一个算子,用这个算子对图像进行滤波。

代码实现

我们首先使用matlab对算法进行了验证,之后根据编写的matlab算法将其编写为C语言代码,以便于部署到嵌入式设备上。

matlab

function I=my_dither(I,height,width)
    for i=1:height-1
        for j=1:width-1
            oldPixel = I(i,j);
            if oldPixel > 128
                newPixel = 255;
            else
                newPixel = 0;
            end
            if newPixel == 0
                quantError = oldPixel;
                I(i,j) = newPixel;
                I(i,j+1) = I(i,j+1) + quantError* 7/16;
                if j-1 >0
                    I(i+1,j-1) = I(i+1,j-1) + quantError* 3/16;
                end
                I(i+1,j) = I(i+1,j) + quantError* 5/16;
                I(i+1,j+1) = I(i+1,j+1) + quantError* 1/16;
            else
                quantError = newPixel - oldPixel;
                I(i,j) = newPixel;
                I(i,j+1) = I(i,j+1) - quantError* 7/16;
                if j-1 >0
                    I(i+1,j-1) = I(i+1,j-1) - quantError* 3/16;
                end
                I(i+1,j) = I(i+1,j) - quantError* 5/16;
                I(i+1,j+1) = I(i+1,j+1) - quantError* 1/16;
            end
        end
    end

c语言

在进行C语言实现的时候,使用定点数进行存储和计算比用浮点数要快得多,但在使用时要注意数据类型能表示的数值范围,避免溢出从而导致的未知错误。

void dither2(uint8_t *image) {
  
  uint16_t i=0,j=0;
  uint8_t oldPixel,newPixel,errPixel;
  uint8_t add_flag = 0;

  for(i=0;i<HEIGHT-1;i++)
  {
    for(j=0;j<WIDTH-1;j++)
    {
      oldPixel = image[i * WIDTH + j];
      if (oldPixel > 128){
        newPixel = 255;
        errPixel=255 - oldPixel;
        add_flag = 0;
      }
      else{
        newPixel = 0;
        errPixel=oldPixel;
        add_flag = 1;
      }
      image[i * WIDTH + j] = newPixel;

      if(add_flag){
        if( image[i * WIDTH + j+1] > 255 - errPixel* 7/16){
          image[i * WIDTH + j+1] = 255;
        }else{
          image[i * WIDTH + j+1] = image[i * WIDTH + j+1] + errPixel* 7/16;
        }
        if(image[(i+1) * WIDTH + j] > 255 - errPixel* 5/16){
          image[(i+1) * WIDTH + j] = 255;
        }else{
          image[(i+1) * WIDTH + j] = image[(i+1) * WIDTH + j] + errPixel* 5/16;
        }
        if(image[(i+1) * WIDTH + j+1] > 255 - errPixel* 1/16){
          image[(i+1) * WIDTH + j+1] = 255;
        }else{
          image[(i+1) * WIDTH + j+1] = image[(i+1) * WIDTH + j+1] + errPixel* 1/16;
        }
        if(j>0){
          if(image[(i+1) * WIDTH + j-1] > 255 - errPixel* 3/16){
            image[(i+1) * WIDTH + j-1] = 255;
          }else{
            image[(i+1) * WIDTH + j-1] = image[(i+1) * WIDTH + j-1] + errPixel* 3/16;
          }
        }
      }else{
        if( image[i * WIDTH + j+1] < errPixel* 7/16){
          image[i * WIDTH + j+1] = 0;
        }else{
          image[i * WIDTH + j+1] = image[i * WIDTH + j+1] - errPixel* 7/16;
        }
        if(image[(i+1) * WIDTH + j] < errPixel* 5/16){
          image[(i+1) * WIDTH + j] = 0;
        }else{
          image[(i+1) * WIDTH + j] = image[(i+1) * WIDTH + j] - errPixel* 5/16;
        }
        if(image[(i+1) * WIDTH + j+1] < errPixel* 1/16){
          image[(i+1) * WIDTH + j+1] = 0;
        }else{
          image[(i+1) * WIDTH + j+1] = image[(i+1) * WIDTH + j+1] - errPixel* 1/16;
        }
        if(j>0){
          if(image[(i+1) * WIDTH + j-1] < errPixel* 3/16){
            image[(i+1) * WIDTH + j-1] = 0;
          }else{
            image[(i+1) * WIDTH + j-1] = image[(i+1) * WIDTH + j-1] - errPixel* 3/16;
          }
        }
      }
    }
  }
}

这里使用了add_flag标志位来判断是进行减操作还是加操作。因为我们这里使用的数据类型为uint8_t,即unsigned char类型,它能够表示的范围为0~255。在进行减操作的时候,我们需要保证减完得到的值不是负数,如果是负数,就将其置零。而在进行加操作的时候,需要判断得到的结果是否会大于255,如果大于255,就将其置为255。

实验结果

matlab

原图
在这里插入图片描述

处理后得到的图像
在这里插入图片描述

C

处理后得到的图像
在这里插入图片描述

#用热敏打印头的打印效果
在这里插入图片描述
Bilibili:通信电子小白
微信公众号:
在这里插入图片描述

下面是我创建的QQ群,欢迎大家进群交流呀!
QQ群:752236617

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐