You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PNG++实现Floyd-Steinberg抖动无效,仅转为灰度图

问题原因

你的代码无法生成抖动效果的核心问题是:使用png::gray_pixel(整数类型)存储中间像素值。Floyd-Steinberg抖动需要传递小数形式的误差,但gray_pixel会自动截断小数部分,导致误差无法正确累积传递,最终只是把图像做了简单的取整灰度化,没有产生抖动的扩散效果。

修复方案

需要用浮点类型的数组临时存储像素值,确保误差的小数部分能被正确传递,处理完成后再转换回png::gray_pixel类型写入图片。

修改后的代码如下:

#include <iostream>
#include "lib/png.hpp"
#include <cmath>
#include <vector>
#include <algorithm> // 用于std::clamp

int main() {
    // 读取原始图像
    png::image<png::gray_pixel> image("input.png");
    int h = image.get_height();
    int w = image.get_width();

    // 创建浮点型二维数组存储像素值,保留小数精度
    std::vector<std::vector<double>> pixel_data(h, std::vector<double>(w));
    for (int y = 0; y < h; ++y) {
        for (int x = 0; x < w; ++x) {
            pixel_data[y][x] = static_cast<double>(image[y][x]);
        }
    }

    // 执行Floyd-Steinberg抖动算法
    for (int y = 0; y < h; ++y) {
        for (int x = 0; x < w; ++x) {
            double old_val = pixel_data[y][x];
            // 取整为0-255的灰度值
            int new_val = static_cast<int>(std::round(old_val));
            // 确保值在合法范围内,避免溢出
            new_val = std::clamp(new_val, 0, 255);
            pixel_data[y][x] = new_val;
            double error = old_val - new_val;

            // 传递误差,使用浮点数组保证精度不丢失
            if (x + 1 < w) {
                pixel_data[y][x+1] += error * 7.0 / 16.0;
            }
            if (y + 1 < h && x - 1 >= 0) {
                pixel_data[y+1][x-1] += error * 3.0 / 16.0;
            }
            if (y + 1 < h) {
                pixel_data[y+1][x] += error * 5.0 / 16.0;
            }
            if (x + 1 < w && y + 1 < h) {
                pixel_data[y+1][x+1] += error * 1.0 / 16.0;
            }
        }
    }

    // 将浮点数据转换回gray_pixel并写入图像
    for (int y = 0; y < h; ++y) {
        for (int x = 0; x < w; ++x) {
            int val = static_cast<int>(std::round(pixel_data[y][x]));
            val = std::clamp(val, 0, 255);
            image[y][x] = static_cast<png::gray_pixel>(val);
        }
    }

    image.write("output.png");
    return 0;
}
关键改动说明
  • 新增std::vector<std::vector<double>> pixel_data存储浮点型像素值,彻底避免误差被整数类型截断。
  • 误差传递操作直接针对浮点数组,保证小数精度完整保留,实现抖动的扩散效果。
  • 使用std::clamp确保像素值始终在0-255的合法范围内,防止溢出导致的图像异常。
  • 将图像变量移至main函数内,避免全局变量初始化可能带来的潜在问题。

内容的提问来源于stack exchange,提问作者zalaxgodd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 19:37:19