none
不透明度マスクを使ってグラデーションさせるとモアレが発生する RRS feed

  • 質問

  • WPFで不透明度マスクを使い塗りつぶした色や画像(PNGやBMP)などをグラデーションしながら透けさるという事をしてみたのですが、そのグラデーションが綺麗にグラデーションにならずモアレが発生してしまいます。

    他の画像編集アプリケーションと比較してもやはりグラデーション部分でクオリティが劣化したような感じがします。

    背景を黒(#000000)や白(#FFFFFF)にした場合や不透明度マスクを使わない通常のグラデーションは綺麗に出ているような気がします。

    しかし、不透明度マスクを使うとグラデーションが段階的に色が変わってるように見えてしまいます。

    いろいろ調べては見たのですがどうしても解決法が分かりません。

    どうかご教示よろしくお願い致します。

    <Window x:Class="LinearOpacity.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:LinearOpacity"
            mc:Ignorable="d"
            Title="MainWindow" Height="500" Width="500">
        <Grid Background="#212121">
            <Rectangle Fill="#408CC1" SnapsToDevicePixels="True" UseLayoutRounding="True" >
                <Rectangle.OpacityMask>
                    <LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
                        <LinearGradientBrush.GradientStops>
                            <GradientStop Offset="0.0" Color="#00000000" />
                            <GradientStop Offset="1.0" Color="#80000000"/>
                        </LinearGradientBrush.GradientStops>
                    </LinearGradientBrush>
                </Rectangle.OpacityMask>
            </Rectangle>
        </Grid>
    </Window>
    上が上記コードを実行した際のWPFアプリの画像、下が画像編集アプリケーションによる不透明度マスクを使用した画像です。



    • 編集済み karapon 2018年12月10日 10:51 コードのミス
    2018年12月10日 10:43

すべての返信

  • 回答ではなく、現象の検証ですが、WPF は単純に色の差分の階調で忠実に塗りつぶしているようですね。

    今回は色の差が 0x80(128) 階調なので、128 色で塗りつぶしている。その境界(色の差)がモアレのように見える。

    一方画像ソフトの方は、色の境界が不規則(ランダムノイズ?)なっているため、グラデーションとしては綺麗に見えるようです。

    拡大してペイントで塗りつぶすとよくわかります。(上が WPF、下が画像ソフトです)



    画像ソフトは、WPF と色の差は同じだけど、境界に不規則なノイズを入れることで綺麗なグラデーションを実現しているのだと思われます。

    追伸:下記のように Ractangle の塗りつぶしにランダム性をいれるとモアレ感がかなりなくなるのがわかると思います。

    <Window x:Class="WpfApp1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            mc:Ignorable="d"
            Title="MainWindow" Height="500" Width="500">
        <Grid Background="#212121">
            <Rectangle x:Name="rectangle1" Fill="#408CC1">
                <Rectangle.OpacityMask>
                    <LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
                        <LinearGradientBrush.GradientStops>
                            <GradientStop Offset="0.0" Color="#00000000" />
                            <GradientStop Offset="1.0" Color="#80000000"/>
                        </LinearGradientBrush.GradientStops>
                    </LinearGradientBrush>
                </Rectangle.OpacityMask>
            </Rectangle>
        </Grid>
    </Window>
    using System;
    using System.Windows;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Drawing;
    namespace WpfApp1
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                Bitmap bitmap = new Bitmap((int)Width, (int)Height);
                Random rnd = new Random();
                for (int x = 0; x < (int)Width; x++)
                {
                    for (int y = 0; y < (int)Height; y++)
                    {
                        int nAlpha = rnd.Next(230, 255); // ここの範囲を広げすぎるとざらつきが目立つようになる
                        bitmap.SetPixel(x, y, System.Drawing.Color.FromArgb(nAlpha, 0x40, 0x8C, 0xC1));
                    }
                }
                IntPtr hbitmap = bitmap.GetHbitmap();
                rectangle1.Fill = new ImageBrush(System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hbitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()));
                DeleteObject(hbitmap);
            }
            [System.Runtime.InteropServices.DllImport("gdi32.dll")]
            public static extern bool DeleteObject(IntPtr hObject);
        }
    }
    

    • 編集済み kenjinoteMVP 2018年12月10日 14:19
    • 回答の候補に設定 AzuleanMVP 2018年12月17日 21:19
    2018年12月10日 12:02
  • モアレの発生原因等わかりやすいご説明と、現象回避のためのソースコード、非常に参考になりました。

    ありがとうございました。

    2018年12月17日 16:01
  • karapon さん、こんにちは。フォーラム オペレーターの立花です。
    MSDN フォーラムへご投稿くださいましてありがとうございます。

    フォーラム オペレーターから 1 点お願いをさせてください。

    問題に対して参考となった返信や、回答に値する返信をいただいた場合は、
    その返信に対して [回答としてマーク] をご設定ください

    同じ問題で後から参照した方が、情報を見つけやすくなりますので、
    ご協力くださいますよう、お願いいたします。


    参考になった投稿には回答としてマークの設定にご協力ください
    MSDN/TechNet Community Support 立花楓

    2018年12月18日 0:25
    モデレータ
  • ご参考までに。

    モアレと言う表現をなさっていますが、バンディング だと思っています。
    画像データは忠実なのですが、表示時に、色深度不足から目が錯覚を起こし、縞模様を感じる、のだと思います。
    ノイズ付加は、画像処理に良くある 視覚的補正 (見た目を重視し データを掻き混ぜる方法)です。
    ピンク1色に見えるが拡大すると白と赤の市松模様だった、と同じ事ですね。
    そして、バンディング対策は見た目補正である事を忘れないで下さい。  拡大縮小や描画エンジンやディスプレーモニター次第で影響を受けます。

    • 編集済み ShiroYuki_Mot 2018年12月19日 3:03 ディスプレーモニターを追加
    2018年12月18日 2:15