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

如何读取非白色像素叠加至另一图像?叠加后白边问题排查

问题描述

我有两张512x512的图像:

  • 第一张是32位深度PNG(白色背景),需要提取其中非白色像素(云层)
  • 第二张是24位深度JPG,作为像素叠加目标

我用C#实现了像素读取与叠加,但生成的BMP图像中叠加的像素出现白边;另外调整判断条件中的Alpha值(从255改为1或100)时,结果会变成和原PNG图像一致,只有Alpha为255时结果接近预期。

代码实现

核心逻辑类

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Weather
{
    public class RadarPixels
    {
        public RadarPixels(Bitmap image1, Bitmap image2)
        {
            ReadSetPixels(image1, image2);
        }

        private void ReadSetPixels(Bitmap image1 , Bitmap image2)
        {
            for(int x = 0; x < image1.Width; x++)
            {
                for(int y = 0; y < image1.Height; y++)
                {
                    Color pixelColor = image1.GetPixel(x, y);
                    if (pixelColor != Color.FromArgb(255,255,255,255))
                    {
                        image2.SetPixel(x, y, pixelColor);
                    }
                }
            }

            image2.Save(@"d:\mynewbmp.bmp");

            image1.Dispose();
            image2.Dispose();
        }
    }
}

调用代码

public Form1()
{
    InitializeComponent();

    RadarPixels rp = new RadarPixels(
        new Bitmap(Image.FromFile(@"D:\1.png")),
        new Bitmap(Image.FromFile(@"D:\2.jpg")));
}

问题原因分析

  1. 白边问题:32位PNG的云层边缘通常存在半透明白色过渡像素(即R=255、G=255、B=255但Alpha<255的像素),当前判断条件仅排除了完全不透明的纯白像素,这些半透明白像素会被保留并叠加到JPG上,最终显示为白边。
  2. Alpha值调整异常:当把判断条件中的Alpha改为1或100时,Color.FromArgb(1,255,255,255)是几乎完全透明的白色,PNG中绝大多数非纯白像素都不等于这个颜色,导致所有非纯白像素(包括半透明白)都被叠加,最终结果和原PNG一致。

解决方法

1. 修正像素判断逻辑

直接排除所有纯白像素(不管Alpha值),只保留有效云层像素:

Color pixelColor = image1.GetPixel(x, y);
// 排除所有RGB为纯白的像素
if (!(pixelColor.R == 255 && pixelColor.G == 255 && pixelColor.B == 255))
{
    image2.SetPixel(x, y, pixelColor);
}

如果需要兼容接近纯白的过渡像素,可添加阈值判断:

int threshold = 240; // 可根据实际情况调整
if (!(pixelColor.R >= threshold && pixelColor.G >= threshold && pixelColor.B >= threshold))
{
    image2.SetPixel(x, y, pixelColor);
}

2. 正确处理半透明像素叠加

目标JPG是24位无Alpha通道,直接SetPixel会丢弃Alpha值,导致半透明像素显示异常。手动计算混合色实现正确叠加:

Color sourcePixel = image1.GetPixel(x, y);
Color targetPixel = image2.GetPixel(x, y);

// 基于Alpha通道计算混合RGB值
int r = (sourcePixel.R * sourcePixel.A + targetPixel.R * (255 - sourcePixel.A)) / 255;
int g = (sourcePixel.G * sourcePixel.A + targetPixel.G * (255 - sourcePixel.A)) / 255;
int b = (sourcePixel.B * sourcePixel.A + targetPixel.B * (255 - sourcePixel.A)) / 255;

Color blendedColor = Color.FromArgb(255, r, g, b);
image2.SetPixel(x, y, blendedColor);

3. 性能优化(可选)

GetPixel和SetPixel性能较低,可使用LockBits直接操作图像内存提升效率:

private void ReadSetPixels(Bitmap image1, Bitmap image2)
{
    Rectangle rect = new Rectangle(0, 0, image1.Width, image1.Height);
    var bmpData1 = image1.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, image1.PixelFormat);
    var bmpData2 = image2.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, image2.PixelFormat);

    IntPtr ptr1 = bmpData1.Scan0;
    IntPtr ptr2 = bmpData2.Scan0;

    int bytes = Math.Abs(bmpData1.Stride) * image1.Height;
    byte[] rgbValues1 = new byte[bytes];
    byte[] rgbValues2 = new byte[bytes];

    System.Runtime.InteropServices.Marshal.Copy(ptr1, rgbValues1, 0, bytes);
    System.Runtime.InteropServices.Marshal.Copy(ptr2, rgbValues2, 0, bytes);

    // 遍历像素:32位PNG是BGRA格式,24位JPG是BGR格式
    for (int y = 0; y < image1.Height; y++)
    {
        for (int x = 0; x < image1.Width; x++)
        {
            int index1 = y * bmpData1.Stride + x * 4;
            int b1 = rgbValues1[index1];
            int g1 = rgbValues1[index1 + 1];
            int r1 = rgbValues1[index1 + 2];
            int a1 = rgbValues1[index1 + 3];

            // 排除纯白像素
            if (!(r1 == 255 && g1 == 255 && b1 == 255))
            {
                int index2 = y * bmpData2.Stride + x * 3;
                // 计算混合色
                int r = (r1 * a1 + rgbValues2[index2 + 2] * (255 - a1)) / 255;
                int g = (g1 * a1 + rgbValues2[index2 + 1] * (255 - a1)) / 255;
                int b = (b1 * a1 + rgbValues2[index2] * (255 - a1)) / 255;

                rgbValues2[index2] = (byte)b;
                rgbValues2[index2 + 1] = (byte)g;
                rgbValues2[index2 + 2] = (byte)r;
            }
        }
    }

    System.Runtime.InteropServices.Marshal.Copy(rgbValues2, 0, ptr2, bytes);
    image1.UnlockBits(bmpData1);
    image2.UnlockBits(bmpData2);

    image2.Save(@"d:\mynewbmp.bmp");
    image1.Dispose();
    image2.Dispose();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 03:45:42