Floyd-Steinberg抖动算法处理图片并热敏打印

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

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

  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,我会尽力回答您的问题。 Floyd-Steinberg抖动算法是一种常用的图像处理算法,可以用来将一张高色彩深度的图片转换为低色彩深度的图片,适用于墨水屏等设备。在QT中,可以通过QImage类来读取和处理图片。 以下是使用Floyd-Steinberg抖动算法处理墨水屏图片的基本步骤: 1. 打开图片 使用QImage类的load()函数打开需要处理图片,例如: ``` QImage image; image.load("image.png"); ``` 2. 转换为灰度图像 将彩色图片转换为灰度图像,可以使用QImage类的convertToFormat()函数实现: ``` image = image.convertToFormat(QImage::Format_Grayscale8); ``` 3. 进行抖动处理 使用Floyd-Steinberg抖动算法对灰度图像进行处理,将每个像素点的值转换为0或1,然后将误差传递给周围的像素点。这里可以用一个二维数组来存储每个像素点的值: ``` int width = image.width(); int height = image.height(); int** pixels = new int*[width]; for(int i = 0; i < width; i++) { pixels[i] = new int[height]; } for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { int oldPixel = qGray(image.pixel(x, y)); int newPixel = oldPixel > 127 ? 255 : 0; pixels[x][y] = newPixel; int error = oldPixel - newPixel; if(x < width - 1) { pixels[x+1][y] += (int)(error * 7 / 16.0); } if(x > 0 && y < height - 1) { pixels[x-1][y+1] += (int)(error * 3 / 16.0); } if(y < height - 1) { pixels[x][y+1] += (int)(error * 5 / 16.0); } if(x < width - 1 && y < height - 1) { pixels[x+1][y+1] += (int)(error * 1 / 16.0); } } } ``` 4. 保存处理后的图片处理后的像素点重新转换为QImage格式,并使用save()函数保存为图片文件: ``` QImage result(width, height, QImage::Format_Grayscale8); for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { result.setPixel(x, y, qRgb(pixels[x][y], pixels[x][y], pixels[x][y])); } } result.save("result.png"); ``` 以上就是使用Floyd-Steinberg抖动算法处理墨水屏图片用QT实现的基本步骤,希望对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zxfeng~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值