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

基于Floyd-Steinberg的Python OpenCV图像抖动白色区域异常问题咨询

Fixing Floyd-Steinberg Dithering Edge Artifacts in OpenCV/Python

Let's break down why you're seeing those unexpected dark spots in white areas (especially the top-right corner) and fix the code step by step:

Key Issues in Your Implementation

  • Reversed Pixel Coordinates: OpenCV/numpy stores images as [row, column] (i.e., [y, x]), but your code uses im[x,y] which swaps the axes. This sends error diffusion to the wrong pixels, causing edge artifacts.
  • Incorrect Width/Height Assignment: img.shape returns (height, width, channels), so width,height,z=img.shape flips your dimensions entirely—this is a major cause of edge misbehavior.
  • Unclamped Pixel Values: When adding quantization error, values can go below 0 or above 255. Since OpenCV uses uint8 arrays, these values wrap around (e.g., 256 becomes 0), creating unexpected dark/light pixels.
  • Out-of-Bounds Access: Your loop allows x+1 or y+1 to go beyond the image dimensions, leading to invalid pixel modifications.

Corrected Code

import cv2
import numpy as np

def set_pixel(im, y, x, new_val):
    # Ensure we stay within 0-255 to prevent overflow
    clamped_val = np.clip(new_val, 0, 255)
    im[y, x] = clamped_val

def quantize(im):
    height, width = im.shape
    # Floyd-Steinberg processes left-to-right, top-to-bottom
    for y in range(height):
        for x in range(width):
            old_pixel = im[y, x]
            # Quantize to 0 or 255
            new_pixel = 0 if old_pixel < 127 else 255
            set_pixel(im, y, x, new_pixel)
            quant_err = old_pixel - new_pixel
            
            # Apply error diffusion only if we're not at the edge
            if x + 1 < width:
                set_pixel(im, y, x+1, im[y, x+1] + quant_err * 7/16)
            if x - 1 >= 0 and y + 1 < height:
                set_pixel(im, y+1, x-1, im[y+1, x-1] + quant_err * 3/16)
            if y + 1 < height:
                set_pixel(im, y+1, x, im[y+1, x] + quant_err * 5/16)
            if x + 1 < width and y + 1 < height:
                set_pixel(im, y+1, x+1, im[y+1, x+1] + quant_err * 1/16)
    return im

# Load image and process channels
img = cv2.imread("/home/user/Downloads/blender_images/truck.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img2 = img.copy()

# Correct shape assignment: height first, then width
height, width, z = img.shape

# Process each color channel separately
blue = img[:, :, 0].copy()  # Make a copy to avoid modifying original image
blue = quantize(blue)
green = img[:, :, 1].copy()
green = quantize(green)
red = img[:, :, 2].copy()
red = quantize(red)
gray1 = quantize(gray.copy())

# Merge channels back
image = cv2.merge((blue, green, red))

# Display results
cv2.imshow('original', img2)
cv2.imshow('merged', image)
cv2.imshow('gray', gray1)
cv2.waitKey(0)
cv2.destroyAllWindows()  # Clean up windows after exit

What Changed?

  1. Fixed Coordinate System: Now set_pixel uses im[y, x] to match numpy/OpenCV's row-column order.
  2. Clamped Pixel Values: np.clip ensures all pixel values stay within the valid 0-255 range, eliminating overflow artifacts.
  3. Edge Safety Checks: We only apply error diffusion if the target pixel is within the image bounds (no more out-of-bounds access).
  4. Copied Channels: We make copies of each color channel before processing to avoid accidentally modifying the original image data.
  5. Cleaned Up Window Handling: Added cv2.destroyAllWindows() to properly close windows when you exit.

This should eliminate those weird dark spots in white areas and give you consistent Floyd-Steinberg dithering across all images.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:44:53