如何使用XAML将彩色图像转换为灰度图像?

5

最好使用XAML,

我需要动态地将灰度滤镜应用于彩色图像,从底部到顶部。也就是说,我希望能够在程序中更改应用于我的图像的灰度滤镜的偏移值。

例如,我想要以编程方式设置图像的50%为彩色(从图像底部到其中间),并将图像的另外50%设置为灰度(例如,从图像中间到其顶部)。

我已经阅读了很多不同的答案,尝试了很多不同的方法,并考虑了很多不同的方法来解决这个问题。

  • 我可以有两个图像,一个位于另一个之上。一个是灰度的,另一个是彩色的。然后我将以编程方式更改灰度图像的大小,以便下面的彩色图像部分显示并为用户创建一种半半的视图。

但是,这种解决方案存在一个我似乎无法解决的问题。当更改灰度图像的高度值时,由于“Stretch”属性设置为Uniform(我不希望将其更改为None),图像会自动重新缩放。

  • 另一种方法是以编程方式更改图像的颜色像素。我以前在这方面有过一些成功,但是对于我现在所尝试的内容来说速度太慢了(理想情况下,我将每50毫秒从灰度更改为用户选择的原始图像颜色,直到达到某个高度)。

  • 第三种方法可能是在图像上应用不透明度掩码,并使用LinearGradientBrush将偏移值更改为所需位置。这是我目前正在使用的代码,它可以工作,但只是将灰色应用于图像而不改变图像的原始颜色为灰度(导致图像颜色变淡):

XAML:

<Image x:Name="myImage" HorizontalAlignment="Left" VerticalAlignment="Top" Source="C:\Users\Clement\Desktop\test.png" Canvas.Left="159" Canvas.Top="81" Width="500" Height="375" >
            <Image.OpacityMask>
                <LinearGradientBrush EndPoint="0.5,0" MappingMode="RelativeToBoundingBox" StartPoint="0.5,1">
                    <GradientStop x:Name="myImageLinearGradientBrushStop" Color="Black"/>
                    <GradientStop Color="Transparent" Offset="1"/>
                </LinearGradientBrush>
            </Image.OpacityMask>
</Image>

在一个重复每50毫秒的timerEventProcessor中的Code-behind代码:

myImageLinearGradientBrushStop.Offset = percent * 0.01;

如之前所提到的,我浏览了许多不同的网站,阅读了很多类似的问题,并尝试了许多不同的答案,仍然无法令人满意地解决这个问题。


听起来你可能想要创建自己的效果,但我不知道你是否可以绑定它们,或者从图像派生并在位图级别添加渐变。 - TheGeneral
嗨,Michael,感谢你抽出时间回复我的问题。我确实想要在XAML中将自己的灰度效果绑定到图像控件上。但是,不幸的是,我不知道从哪里开始。如果你有任何想法,请务必告诉我。 - user9375565
2个回答

5
以下 XAML 使用带有两行的网格来显示两个图像,位于彼此之上。顶部图像的宽度和高度绑定到底部图像的大小,底部图像跨越整个网格的两行。内部网格用于裁剪顶部图像。
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>

    <Image x:Name="image" Grid.RowSpan="2" Source="..."/>

    <Grid>
        <Image Width="{Binding ActualWidth, ElementName=image}"
               Height="{Binding ActualHeight, ElementName=image}"
               HorizontalAlignment="Center" VerticalAlignment="Top">
            <Image.Source>
                <FormatConvertedBitmap Source="{Binding Source, ElementName=image}"
                                       DestinationFormat="Gray8"/>
            </Image.Source>
        </Image>
    </Grid>
</Grid>

你好Clemens, 非常感谢您为我解决这个问题。 不幸的是,您的代码片段并没有真正解决我的问题。第二张图像(灰度)似乎没有正确生成,并且看起来是透明的。 然而,我一直在考虑第四种方法来完成这个任务:
  • 生成101张图像(从原彩色图像的0到100%高度)。这可能需要一分钟左右,具体取决于用于创建灰度图像的算法。
  • 将这些图像存储在列表中。
  • 根据所需高度的百分比快速切换到正确的图像。
- user9375565
1
“不太清楚生成的是否正确,看起来好像是不可见的”并不是一个很清晰的问题描述。对我来说,FormatConvertedBitmap运行良好。 - Clemens
你好Clemens, 如果我没有表达清楚,我向你道歉。我的意思是,“第二张图像(灰度)似乎没有正确生成,看起来是不可见的”,使用你的代码,我能够通过将“Source =”...“”替换为正确的图像路径来显示我想要展示的图像,然而,第二个应该是Gray8的图像没有在窗体上显示(只有一个与原始图像相同大小的空矩形被表示)。然而,现在我想起来了,这可能是由于我使用的图像(具有透明背景的png)导致的。 - user9375565
如果您使用上述确切的XAML,则会在彩色图像的顶部显示灰度图像的上半部分(即第一行)。通过更改相对行高,您可以更改可见部分。 - Clemens
如果您删除高度绑定,则图像的高度当然不相同。正如所说,只需设置第一行网格的高度,可以是相对或绝对的。 - Clemens
显示剩余4条评论

2
感谢Clemens的帮助,我成功解决了我的问题!
以下是最终的XAML代码,供有兴趣的人参考:
<Grid Width="500" Height="375">
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>

            <Image x:Name="image" Grid.RowSpan="2" Source="C:\Users\Clement\Desktop\test_image.png" />

            <Grid Margin="0,0,0,166" Grid.RowSpan="2">
                <Image Width="{Binding ActualWidth, ElementName=image}"
           Height="{Binding ActualHeight, ElementName=image}"
           HorizontalAlignment="Center" VerticalAlignment="Top">
                    <Image.Source>
                        <FormatConvertedBitmap Source="{Binding Source, ElementName=image}"
                                   DestinationFormat="Gray8"/>
                    </Image.Source>
                    <Image.OpacityMask>
                        <ImageBrush ImageSource="C:\Users\Clement\Desktop\test_image.png"/>
                    </Image.OpacityMask>
                </Image>
            </Grid>
        </Grid>

在这里,我只是将OpacityMask添加到Gray8图像中,以恢复其透明度。

编码愉快!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接