DOBON.NET DOBON.NETプログラミング掲示板過去ログ

ペイントのような塗りつぶし

環境/言語:[Windows XP/Visual Studio 2005/Visual C++ 2005/.NET Framework 2.0]
分類:[.NET]

お久しぶりです。いつもお世話になっています。
ただ今、ペイントのような塗りつぶしが簡単にできる方法を探しています。

-ここから今までにやってきたこと-

本来の目的は、図の左側の画像を読み込んで、図の右側の状態にして、
黄色にあたる部分を透過色にしたいと思っています。
(図の左のAの中以外の赤を透過色にしたい)
今までに試した方法は

Bitmap^ bmp = gcnew Bitmap("ファイルパス");
bmp->MakeTransparent(System::Drawing::Color::Red);
Graphics^ brendG = Graphics::FromImage(this->BackgroundImage);
brendG->DrawImage(bmp,0,0);

この方法では、Aの中も透明になってしまいます。

-ここから質問-

なので、図の左側の画像を右側するためにペイントで塗りつぶしをしたときのようになればいいと思っています。
(赤続きは黄色に塗りかえる)

分かりにくくなってしまいましたが、Aの中以外の赤を黄色に変えることができる方法が知りたいです。
どなたか回答をよろしくお願いします。
添付ファイル: 1277465122.png (8 KB)
■No26983に返信(masaさんの記事)
> 分かりにくくなってしまいましたが、Aの中以外の赤を黄色に変えることができる方法が知りたいです。

クリッピング領域でマスクして描画するとかすればどうですか?

クリッピング領域を指定して画像の一部を表示するhttp://dobon.net/vb/dotnet/graphics/setclip.html
やじゅさん、回答ありがとうございます。
質問に書いていなかったのが原因ですが、画像ファイルは1つではなく、何種類かあるので、領域を指定することが困難になってしまいます。
塗りつぶしができる方法を教えていただけると幸いです。
気合いと根性で塗っていくとか。
私はVBしかできないので,VBで書くと下のようになります。
アルゴリズムは「スキャンライン シードフィル」で検索すればたくさん見つかります。

Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
        Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        Dim bitmap = New Bitmap(Me.ClientRectangle.Width, Me.ClientRectangle.Height)
        Using g As Graphics = Graphics.FromImage(bitmap)
            g.DrawString("A", New Font(Me.Font.Name, 200), Brushes.Black, New Point(0, 0))
        End Using
        Me.BackgroundImage = bitmap
        Me.Show()
        For Each c As Color In {Color.Blue, Color.Red, Color.Green, Color.Yellow, Color.White}
            paint(bitmap, New Point(50, 30), c)
        Next
    End Sub

    Public Shadows Sub paint(ByRef bitmap As Bitmap, ByVal point As Point, ByVal color As Color)
        Dim bg As Color = bitmap.GetPixel(point.X, point.Y)
        Dim buf As New Queue(Of Point)
        buf.Enqueue(point)
        Using g As Graphics = Graphics.FromImage(bitmap)
            Using Pen As New Pen(color)
                While buf.Count > 0
                    Dim p As Point = buf.Dequeue
                    If bitmap.GetPixel(p.X, p.Y) = bg Then
                        Dim rx As Integer = p.X
                        Dim lx As Integer = p.X
                        While rx < bitmap.Width - 1
                            If bitmap.GetPixel(rx + 1, p.Y) <> bg Then
                                Exit While
                            End If
                            rx += 1
                        End While
                        While lx > 0
                            If bitmap.GetPixel(lx - 1, p.Y) <> bg Then
                                Exit While
                            End If
                            lx -= 1
                        End While
                        g.DrawLine(Pen, lx, p.Y, rx, p.Y)
                        Me.Refresh()
                        If p.Y > 0 Then
                            scanLine(bitmap, buf, lx, rx, p.Y - 1, bg)
                        End If
                        If p.Y < bitmap.Height - 1 Then
                            scanLine(bitmap, buf, lx, rx, p.Y + 1, bg)
                        End If
                    End If
                End While
            End Using
        End Using
    End Sub

    Private Sub scanLine(ByRef bitmap As Bitmap, ByVal buf As Queue(Of Point), ByVal lx As Integer, ByVal rx As Integer, ByVal y As Integer, ByVal bg As Color)
        While lx < rx
            While lx < rx
                If bitmap.GetPixel(lx + 1, y) = bg Then
                    Exit While
                End If
                lx += 1
            End While
            While lx < rx
                If bitmap.GetPixel(lx + 1, y) <> bg Then
                    Exit While
                End If
                lx += 1
            End While
            buf.Enqueue(New Point(lx, y))
            lx += 1
        End While
    End Sub

End Class
返信が遅くなりましたが、YASさん、回答ありがとうございます。
せっかくコードまで書いていただいたのに申し訳ありませんが、スキャンラインの意味があまりよくわかりませんでした。
今、考えていることは、X,Y位置の色を知ることができれば…と、思うのですが、
よい方法はありませんか?
どなたか回答お願いします。
> せっかくコードまで書いていただいたのに申し訳ありませんが、スキャンラインの意味があまりよくわかりませんでした。

昔のベーシックのPAINT文などで使われていた,塗りつぶしの有名なアルゴリズムですが...

> 今、考えていることは、X,Y位置の色を知ることができれば…と、思うのですが、
> よい方法はありませんか?

上の塗りつぶしのコードにもありましたが,BitmapクラスのGetPixelメソッドで色を取得できます。
Bitmap::GetPixelとBitmap::SetPixelを使うことで、簡単な塗りつぶしができるようになりました。
YASさん、やじゅさん、回答ありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板