Görüntüyü Düzeltme


114

Popüler bir resim düzenleme yazılımında yamalar (resim işlemede kullanılan bir terim olduğu, bir özelliği vardır inpainting @ mınxomaτ belirttiği gibi.) Bir görüntünün, seçilen bir bölgeyi, bilgilere göre dış yamanın. Ve sadece bir program olduğu düşünüldüğünde oldukça iyi bir iş çıkarıyor. Bir insan olarak, bazen bir şeyin yanlış olduğunu görebilirsiniz, ancak gözlerinizi sıkarsanız veya kısa bir bakış alırsanız, yama boşluğu oldukça iyi dolduruyor gibi görünmektedir .

popüler resim düzenleme yazılımı ile örnek

Meydan okuma

Bir görüntü ve görüntünün dikdörtgen alanını belirten bir maske göz önüne alındığında (aynı zamanda görüntü veya başka bir tercih edilen biçim olarak) yamalanmalı, programınız belirtilen alanı diğerleriyle karıştırmaya çalışan bir yama ile doldurmaya çalışmalıdır. görüntü. Program, belirtilen alandaki orijinal görüntünün bilgilerini kullanamaz.

Yamanın her zaman en azından kenarlardan uzakta olduğunu ve görüntünün üstünden ve altından yüksekliği olduğunu varsayalım. Bu, bir yamanın maksimum alanının tüm görüntünün 1 / 9'u olduğu anlamına gelir.

Lütfen algoritmanızın nasıl çalıştığı hakkında kısa bir açıklama ekleyin.

oylama

Seçmenlerden algoritmaların ne kadar iyi performans gösterdiğine karar vermeleri ve buna göre oy kullanmaları isteniyor.

Yargılama konusunda bazı öneriler: (Yine, bazı kriterler için teşekkürler @ mınxomaτ.)

  • Gözlerini kısarsan ve resim iyi görünüyor mu?
  • Yamanın yerini tam olarak söyleyebilir misin?
  • Görüntü arka planından ve çevresindeki alandan yapılar ve dokular ne kadar iyi devam ediyor?
  • Düzenlenen alan ne kadar başıboş yanlış renk piksel içeriyor?
  • Bölgede, oraya ait gibi görünmeyen eşit renkli bloklar / bloklar var mı?
  • Düzenlenen alan, görüntünün geri kalanına kıyasla şiddetli renk / kontrast veya parlaklık kaymalarına sahip mi?

Geçerlilik kriteri

Bir gönderimin geçerli olması için, çıkış görüntüsünün belirtilen alanın dışındaki giriş görüntüsüyle tam olarak eşleşmesi gerekir.

Test durumu

Soldaki kaynak görüntü, sağdaki ilgili maske:


1
Maske girişini metin argümanları olarak kabul edebilir miyiz (örn. inpaint.exe left top width height img.jpg)?
mınxomaτ

1
Elbette, giriş / çıkış formatı gerçekten o kadar da önemli değil, çünkü algoritmanızın performansının ilk olarak önemli olduğu bir popülerlik yarışması .
kusur,

24
Bu çok pratik bir zorluktur. Sonuçların GIMP ve diğer açık kaynaklı görüntü düzenleme yazılımlarında kullanılan mevcut algoritmalardan daha iyi olması mümkündür. Servet, Şöhret ve Zafer senin olabilir!
Sparr

6
@Sparr ve nihayet çirkin filigranlar indirilen ortamlardan kaldırılabilir;)
Andras Deak

2
Yerleşikler tamamen iyi, ama çok popüler olacaklarından şüphem yok.
kusur

Yanıtlar:


142

AutoIt , VB

Giriş

Bu, A. Criminisi, P. Perez (Cambridge Microsoft Research Ltd.) ve K. Toyama (Microsoft) [X] tarafından geliştirilen Örnek Bazlı Boyamama algoritması ile Nesne Kaldırma'nın bir uygulamasıdır . Bu algoritma yüksek bilgi görüntülerini (ve video karelerini) hedeflemektedir ve yapısal yeniden yapılanma ile organik yeniden yapılanma arasındaki dengeyi hedeflemektedir. Bu cevabın paragrafları, bu cevabı daha bağımsız hale getirmek için orijinal metinden tam alıntılar içermektedir (artık resmi olarak mevcut değildir).

Algoritma

Hedef : Seçilen ( maskeli ) bir alanı (tercihen görsel olarak ayrılmış bir ön plan nesnesini) görsel olarak makul arka planlarla değiştirin.

Önceki çalışmalarda, bazı araştırmacılar doku sentezini büyük görüntü bölgelerini "saf" dokularla - tekrarlayan iki boyutlu dokusal desenleri ılımlı stokastik ile doldurmanın bir yolu olarak görüyorlardı. Bu, küçük bir saf doku kaynağı örneği verilen doku adının sonsuzluğunu kopyalamayı amaçlayan büyük bir doku-sentez araştırması kütlesine dayanmaktadır [1] [8] [9] [10] [11] [12] [14] [15] [16] [19] [22] .

Bu teknikler tutarlı dokuları çoğaltmakta olduğu kadar etkilidirler, çoğu zaman doğrusal yapılardan ve kompozit dokulardan oluşan gerçek dünya sahnelerinin fotoğraflarında delikler doldurmakta zorluk çekerler - mekansal olarak etkileşime giren çoklu dokular [23] . Asıl sorun, görüntü bölgeleri arasındaki sınırların farklı dokular arasındaki karşılıklı etkilerin karmaşık bir ürünü olmasıdır. Saf dokuların iki boyutlu yapısının aksine, bu sınırlar daha tek boyutlu veya doğrusal görüntü yapıları olarak düşünülebilecek şeyleri oluşturur.

Görüntü inpainting teknikleri doğrusal yapılar (denilen çoğaltarak görüntülerdeki delikleri doldurmak isophotes içinde inpainting difüzyon yoluyla hedef bölgeye literatüründe). Fiziksel ısı akışının kısmi diferansiyel denklemlerinden ilham alırlar ve restorasyon algoritmaları olarak ikna edici çalışırlar. Bunların dezavantajı, difüzyon işleminin belirgin olan bazı bulanıklıkları ortaya çıkarmasıdır.

incir.  2

Doldurulacak bölge, yani hedef bölge Ω ile gösterilir ve konturu δΩ ile gösterilir. Kontur, algoritma ilerledikçe içe doğru gelişir ve bu yüzden buna "dolgu cephesi" de denir. Algoritma boyunca sabit kalan kaynak bölgesi, doldurma işleminde kullanılan numuneleri sağlar. Şimdi, yapı ve dokunun nasıl örnek-temelli bir sentez tarafından uygun bir şekilde ele alındığını göstermek için algoritmanın tek bir yinelemesine odaklanıyoruz. P noktasındaki ortalamanın templatep Ω square kare şablonunun doldurulacağını varsayalım. Kaynak bölgeden gelen en iyi eşleşme örneği, zaten alreadyp ile doldurulmuş kısımlara en çok benzeyen Ψqˆ ˆ comes yamasından gelir. Şekildeki örnekte. 2b, görüyoruz ki eğer imagep bir resim kenarının devamında yatıyorsa, En muhtemel en iyi eşleşmeler aynı (veya benzer şekilde renkli) bir kenar boyunca uzanacaktır (örneğin, şekil 2c'deki Ψq 've Ψq' '). İzofoiti içe doğru ilerletmek için gereken tek şey, kalıbın en iyi eşleşen kaynak yamadan basit bir aktarımıdır (şek. 2d). İzofor oryantasyonunun otomatik olarak korunduğuna dikkat edin. Şekilde, orijinal kenarın hedef konturu δΩ ile ortogonal olmamasına rağmen, yayılan yapı kaynak bölgeyle aynı yönelimi korumuştur.

Uygulama ve Algoritma Detayları

Bu uygulamanın işlevselliği, bir ana bilgisayar programından bir binary olarak bırakılan ve daha sonra karanlığa IID'yi çağırarak anında çağrılan bir ActiveX COM DLL'sinde kapsüllenir. Bu özel durumda, API VisualBasic ile yazılmıştır ve herhangi bir COM-etkin dilden çağrılabilir. Kodun aşağıdaki bölümü ikili dosyayı bırakır:

Func deflate($e=DllStructCreate,$f=@ScriptDir&"\inpaint.dll")
    If FileExists($f) Then Return
    !! BINARY CODE OMITTED FOR SIZE REASONS !!
    $a=$e("byte a[13015]")
    DllCall("Crypt32.dll","bool","CryptStringToBinaryA","str",$_,"int",0,"int",1,"struct*",$a,"int*",13015,"ptr",0,"ptr",0)
    $_=$a.a
    $b=$e('byte a[13015]')
    $b.a=$_
    $c=$e("byte a[14848]")
    DllCall("ntdll.dll","int","RtlDecompressBuffer","int",2,"struct*",$c,"int",14848,"struct*",$b,"int",13015,"int*",0)
    $d=FileOpen(@ScriptDir&"\inpaint.dll",18)
    FileWrite($d,Binary($c.a))
    FileClose($d)
EndFunc

Kütüphane daha sonra CLSID ve IID kullanılarak başlatılır:

Local $hInpaintLib = DllOpen("inpaint.dll")
Local $oInpaintLib = ObjCreate("{3D0C8F8D-D246-41D6-BC18-3CF18F283429}", "{2B0D9752-15E8-4B52-9569-F64A0B12FFC5}", $hInpaintLib)

Kütüphane GDIOBJECT tutamacını, özellikle herhangi bir GDI / + bitmap'in (dosyalar, akışlar vb.) DIBSection'ını kabul eder. Belirtilen görüntü dosyası yüklenir ve Scan0giriş görüntüsü boyutlarından oluşturulan boş bir bitmap üzerine çizilir .

Bu uygulama için giriş dosyası, maskeli görüntü verilerini içeren herhangi bir GDI / + uyumlu dosya formatıdır. Maskesi (ler) giriş görüntüsünde bir ya da daha fazla eşit ölçülü renkli bir bölgesidir. Kullanıcı maske için bir RGB renk değeri sağlar, yalnızca tam olarak bu renk değerine sahip pikseller eşleşir. Varsayılan maskeleme rengi yeşildir (0, 255, 0). Tüm maskelenmiş bölgeler birlikte kaldırılıp doldurulacak olan hedef bölgeyi (represent) temsil eder. Kaynak bölge, Φ, görüntünün tamamı eksi hedef bölge olarak tanımlanır (Φ = I − Ω).

Daha sonra, tüm örnek bazlı doku sentezinde [10] olduğu gibi, şablon penceresinin Ψ (aka " tarama yarıçapı ") boyutu belirtilmelidir. Bu uygulama varsayılan olarak 6² piksel boyutunda bir pencere boyutu sağlar, ancak pratikte kullanıcının kaynak bölgedeki en büyük ayırt edici doku öğesinden veya “texel” den biraz daha büyük olmasını ayarlamasını gerektirir. Orijinal algoritmaya yapılan ilave bir değişiklik, değiştirilecek piksel alanını yeni bir tek biçimli renkle belirleyen, kullanıcı tarafından tanımlanabilir " blok boyutu " dır . Bu, hızı arttırır ve kaliteyi düşürür. 1 pikselden daha büyük blok büyüklüklerinin son derece düzgün alanlar (su, kum, kürk vb.) İle kullanılması amaçlanmıştır, ancak max maks. .5x blok boyutu (maskeye bağlı olarak imkansız olabilir).

Algoritmayı 1 bit görüntülerde durduramamak için, 5 renkten küçük bir görüntü her alındığında, pencere boyutu 10x büyütülür.

Bu parametreler belirlendikten sonra, bölge doldurma işleminin geri kalanı tamamen otomatiktir. Algoritmamızda, her piksel bir renk değeri (veya piksel doldurulmamışsa “boş”) ve piksel değerine olan güvenimizi yansıtan ve bir piksel dolduğunda donmuş olan bir güven değeri tutar. Algoritmanın seyri boyunca, doldurma cephesi boyunca yamalar da dolduruldukları sırayı belirleyen geçici bir öncelik değeri verilir. Ardından algoritmamız, tüm pikseller doluncaya kadar aşağıdaki üç adımı yineler.

Adım 1: Hesaplama eki öncelikleri

Doldurma sırası parametrik olmayan doku sentezi için çok önemlidir [1] [6] [10] [13] . Şimdiye kadar, varsayılan favori, hedef bölgenin dıştan içe içe, eşmerkezli katmanlar halinde sentezlendiği “soğan kabuğu” yöntemi olmuştur. Algoritmamız bu görevi, tamamen dolum cephesindeki her yamaya atanan öncelik değerlerine bağlı olan en iyi ilk dolum algoritması ile gerçekleştirir. Öncelikli hesaplama, güçlü kenarların devamında olan ve yüksek güvenilirlikteki piksellerle çevrili olan yamalara doğru önyargılıdır, bu pikseller -2 değeri ile işaretlenmiş sınırdır. Aşağıdaki kod öncelikleri yeniden hesaplar:

For j = m_top To m_bottom: Y = j * m_width: For i = m_left To m_right
    If m_mark(Y + i) = -2 Then m_pri(Y + i) = ComputeConfidence(i, j) * ComputeData(i, j)
Next i: Next j

Bazı p ∈ δΩ için p noktasında ortalanan bir yama Ψp verildiğinde (bakınız şekil 3), önceliği P (p) hesaplanan güven ( ComputeConfidence, veya C (p) ) ve veri terimi ( ComputeData, veya D (p) ) nerede

, nerede

| Ψp | Ψp alanı, α normalizasyon faktörüdür (örneğin, tipik gri seviye görüntü için α = 255) ve np, p noktasındaki öne δΩ ortogonal bir birim vektördür. Öncelik, her sınır yaması için, hedef bölgenin sınırındaki her piksel için ayrı yamalar ile hesaplanır.

Olarak uygulandı

Private Function ComputeConfidence(ByVal i As Long, ByVal j As Long) As Double
    Dim confidence As Double
    Dim X, Y As Long

    For Y = IIf(j - Winsize > 0, j - Winsize, 0) To IIf(j + Winsize < m_height - 1, j + Winsize, m_height - 1): For X = IIf(i - Winsize > 0, i - Winsize, 0) To IIf(i + Winsize < m_width - 1, i + Winsize, m_width - 1)
        confidence = confidence + m_confid(Y * m_width + X)
    Next X: Next Y

    ComputeConfidence = confidence / ((Winsize * 2 + 1) * (Winsize * 2 + 1))
End Function

Private Function ComputeData(ByVal i As Long, ByVal j As Long) As Double
    Dim grad As CPOINT
    Dim temp As CPOINT
    Dim grad_T As CPOINT
    Dim result As Double
    Dim magnitude As Double
    Dim max As Double
    Dim X As Long
    Dim Y As Long
    Dim nn As CPOINT
    Dim Found As Boolean
    Dim Count, num As Long
    Dim neighbor_x(8) As Long
    Dim neighbor_y(8) As Long
    Dim record(8) As Long
    Dim n_x As Long
    Dim n_y As Long
    Dim tempL As Long
    Dim square As Double

    For Y = IIf(j - Winsize > 0, j - Winsize, 0) To IIf(j + Winsize < m_height - 1, j + Winsize, m_height - 1): For X = IIf(i - Winsize > 0, i - Winsize, 0) To IIf(i + Winsize < m_width - 1, i + Winsize, m_width - 1)
        If m_mark(Y * m_width + X) >= 0 Then
            Found = False
            Found = m_mark(Y * m_width + X + 1) < 0 Or m_mark(Y * m_width + X - 1) < 0 Or m_mark((Y + 1) * m_width + X) < 0 Or m_mark((Y - 1) * m_width + X) < 0
            If Found = False Then
                temp.X = IIf(X = 0, m_gray(Y * m_width + X + 1) - m_gray(Y * m_width + X), IIf(X = m_width - 1, m_gray(Y * m_width + X) - m_gray(Y * m_width + X - 1), (m_gray(Y * m_width + X + 1) - m_gray(Y * m_width + X - 1)) / 2#))
                temp.Y = IIf(Y = 0, m_gray((Y + 1) * m_width + X) - m_gray(Y * m_width + X), IIf(Y = m_height - 1, m_gray(Y * m_width + X) - m_gray((Y - 1) * m_width + X), (m_gray((Y + 1) * m_width + X) - m_gray((Y - 1) * m_width + X)) / 2#))
                magnitude = temp.X ^ 2 + temp.Y ^ 2
                If magnitude > max Then
                    grad.X = temp.X
                    grad.Y = temp.Y
                    max = magnitude
                End If
            End If
        End If
    Next X: Next Y

    grad_T.X = grad.Y
    grad_T.Y = -grad.X

    For Y = IIf(j - 1 > 0, j - 1, 0) To IIf(j + 1 < m_height - 1, j + 1, m_height - 1): For X = IIf(i - 1 > 0, i - 1, 0) To IIf(i + 1 < m_width - 1, i + 1, m_width - 1): Count = Count + 1
        If X <> i Or Y <> j Then
            If m_mark(Y * m_width + X) = -2 Then
                num = num + 1
                neighbor_x(num) = X
                neighbor_y(num) = Y
                record(num) = Count
            End If
        End If
    Next X: Next Y

    If num = 0 Or num = 1 Then
        ComputeData = Abs((0.6 * grad_T.X + 0.8 * grad_T.Y) / 255)
    Else
        n_x = neighbor_y(2) - neighbor_y(1)
        n_y = neighbor_x(2) - neighbor_x(1)
        square = CDbl(n_x ^ 2 + n_y ^ 2) ^ 0.5
        ComputeData = Abs((IIf(n_x = 0, 0, n_x / square) * grad_T.X + IIf(n_y = 0, 0, n_y / square) * grad_T.Y) / 255)
    End If
End Function

C (p) güven terimi, p pikselini çevreleyen güvenilir bilgi miktarının bir ölçüsü olarak düşünülebilir. Amaç, ilk önce, daha önce doldurulmuş pikselleri (veya asla hedef bölgenin bir parçası olmayan) tercih edilen ek tercihlerle, daha önce piksellerinin daha çok doldurduğu yamaları doldurmaktır.

Bu otomatik olarak doldurma cephesi boyunca belirli şekillere yönelik tercihleri ​​içerir. Örneğin, hedef bölgenin köşelerini ve ince çubuklarını içeren yamalar, orijinal görüntüden daha fazla pikselle çevrili oldukları için ilk önce doldurulma eğiliminde olacaktır. Bu yamalar eşleşecek şekilde daha güvenilir bilgi sağlar. Tersine, hedef bölgeye sıçrayan dolgulu piksellerin “yarımadalarının” ucundaki yamalar, çevreleyen piksellerin daha fazlası doldurulana kadar bir kenara ayrılma eğiliminde olacaktır. istenen konsantrik dolum sırasını zorlar.

Dolum ilerledikçe, hedef bölgenin dış katmanlarındaki pikseller daha büyük güven değerleri ile karakterize olma eğilimindedir ve bu nedenle daha erken doldurulur; Hedef bölgenin ortasındaki pikseller daha az güven değerine sahip olacaktır. D (p) veri terimi, her bir iterasyonda öne itting isophote'ların vurduğu kuvvetin bir fonksiyonudur. Bu terim, bir izofobun "içine aktığı" yamanın önceliğini arttırır. Bu faktör algoritmamızda temel öneme sahiptir çünkü lineer yapıları ilk önce sentezlenmeye teşvik eder ve bu nedenle güvenli bir şekilde hedef bölgeye yayılır. Kırık çizgiler bağlanma eğilimindedir, bu nedenle görme psikolojisinin “Bağlantı İlkesi” nin farkına varır [7] [17] .

Doldurma sırası, görüntü özelliklerine bağlıdır ve “kırık yapı” artefaktları riskini ortadan kaldıran ve aynı zamanda pahalı bir yama kesme basamağı [9] veya bulanıklığa neden olan bir karıştırma basamağı [19 ] olmadan bloklu artifakları azaltan organik bir sentez işlemiyle sonuçlanır. ] .

Adım 2: Doku ve yapı bilgisinin yayılması

Doldurma cephesinde ( sınır ) tüm öncelikler hesaplandıktan sonra, en yüksek önceliğe sahip Ψpˆ yaması bulunur. Daha sonra kaynak bölgeden data çıkarılan verilerle dolduruyoruz. Kaynak dokuyu doğrudan örnekleyerek görüntü dokusunu yayıyoruz. Benzer [10] , biz Ψp en çok benzeyen bu yama için kaynak bölgesinde arayın. Resmi olarak

, nerede

İki genel yamalar Ψa ve db arasındaki d (Ψa, Ψb) mesafesi, iki yamada önceden doldurulmuş piksellerin kare farklılıklarının (SSD) toplamı olarak tanımlanır. Bu aşamada başka bir analiz veya manipülasyon ( özellikle bulanıklaşma yok ) yapılmaz. Bu hesaplama ana döngü döngüsünde çalışır ve aşağıdaki şekilde uygulanır:

Maksimum önceliği almak:

For j = m_top To m_bottom: Jidx = j * m_width: For i = m_left To m_right
    If m_mark(Jidx + i) = -2 And m_pri(Jidx + i) > max_pri Then
        pri_x = i
        pri_y = j
        max_pri = m_pri(Jidx + i)
    End If
Next i: Next j

En benzer yamayı bulmak:

min = 99999999

For j = PatchT To PatchB: Jidx = j * m_width: For i = PatchL To PatchR
    If m_source(Jidx + i) Then
        sum = 0
        For iter_y = -Winsize To Winsize: target_y = pri_y + iter_y
            If target_y > 0 And target_y < m_height Then
                target_y = target_y * m_width: For iter_x = -Winsize To Winsize: target_x = pri_x + iter_x
                    If target_x > 0 And target_x < m_width Then
                        Tidx = target_y + target_x
                        If m_mark(Tidx) >= 0 Then
                            source_x = i + iter_x
                            source_y = j + iter_y
                            Sidx = source_y * m_width + source_x
                            temp_r = m_r(Tidx) - m_r(Sidx)
                            temp_g = m_g(Tidx) - m_g(Sidx)
                            temp_b = m_b(Tidx) - m_b(Sidx)
                            sum = sum + temp_r * temp_r + temp_g * temp_g + temp_b * temp_b
                        End If
                    End If
                Next iter_x
            End If
        Next iter_y

        If sum < min Then: min = sum: patch_x = i: patch_y = j
    End If
Next i: Next j

Adım 3: Güven değerlerini güncelleme

Ψpˆ yaması yeni piksel değerleriyle doldurulduktan sonra, (pˆ ile sınırlanan alanda C (p) güveni aşağıdaki gibi güncellenir:

Bu basit güncelleme kuralı, görüntüye özgü parametreler olmadan dolum önündeki yamaların göreceli güvenini ölçmemizi sağlar. Dolum ilerledikçe, güven değerleri azalır, bu da hedef bölgenin merkezine yakın piksellerin renk değerlerinden daha az emin olduğumuzu gösterir. Buraya uygulandı (gerekli tüm güncellemelerle birlikte):

x0 = -Winsize
For iter_y = -Winsize To Winsize: For iter_x = -Winsize To Winsize
    x0 = patch_x + iter_x
    y0 = patch_y + iter_y
    x1 = pri_x + iter_x
    y1 = pri_y + iter_y
    X1idx = y1 * m_width + x1
    If m_mark(X1idx) < 0 Then
        X0idx = y0 * m_width + x0
        PicAr1(x1, y1) = m_color(X0idx)
        m_color(X1idx) = m_color(X0idx)
        m_r(X1idx) = m_r(X0idx)
        m_g(X1idx) = m_g(X0idx)
        m_b(X1idx) = m_b(X0idx)
        m_gray(X1idx) = CDbl((m_r(X0idx) * 3735 + m_g(X0idx) * 19267 + m_b(X0idx) * 9765) / 32767)
        m_confid(X1idx) = ComputeConfidence(pri_x, pri_y)
    End If
Next iter_x: Next iter_y

For Y = IIf(pri_y - Winsize - 2 > 0, pri_y - Winsize - 2, 0) To IIf(pri_y + Winsize + 2 < m_height - 1, pri_y + Winsize + 2, m_height - 1): Yidx = Y * m_width: For X = IIf(pri_x - Winsize - 2 > 0, pri_x - Winsize - 2, 0) To IIf(pri_x + Winsize + 2 < m_width - 1, pri_x + Winsize + 2, m_width - 1)
    m_mark(Yidx + X) = IIf(PicAr1(X, Y).rgbRed = MaskRed And PicAr1(X, Y).rgbgreen = MaskGreen And PicAr1(X, Y).rgbBlue = MaskBlue, -1, Source)
Next X: Next Y

For Y = IIf(pri_y - Winsize - 2 > 0, pri_y - Winsize - 2, 0) To IIf(pri_y + Winsize + 2 < m_height - 1, pri_y + Winsize + 2, m_height - 1): Yidx = Y * m_width: For X = IIf(pri_x - Winsize - 2 > 0, pri_x - Winsize - 2, 0) To IIf(pri_x + Winsize + 2 < m_width - 1, pri_x + Winsize + 2, m_width - 1)
    If m_mark(Yidx + X) = -1 Then
        Found = (Y = m_height - 1 Or Y = 0 Or X = 0 Or X = m_width - 1) Or m_mark(Yidx + X - 1) = Source Or m_mark(Yidx + X + 1) = Source Or m_mark((Y - 1) * m_width + X) = Source Or m_mark((Y + 1) * m_width + X) = Source
        If Found Then: Found = False: m_mark(Yidx + X) = -2
    End If
Next X: Next Y

For i = IIf(pri_y - Winsize - 3 > 0, pri_y - Winsize - 3, 0) To IIf(pri_y + Winsize + 3 < m_height - 1, pri_y + Winsize + 3, m_height - 1): Yidx = i * m_width: For j = IIf(pri_x - Winsize - 3 > 0, pri_x - Winsize - 3, 0) To IIf(pri_x + Winsize + 3 < m_width - 1, pri_x + Winsize + 3, m_width - 1)
    If m_mark(Yidx + j) = -2 Then m_pri(Yidx + j) = ComputeConfidence(j, i) * ComputeData(j, i)
Next j: Next i

Komple Kod

İşte çalıştırılabilir kod, kitaplıkların kaynak koduyla birlikte yorum olarak tamamlandı.

Kod tarafından çağrılır

inpaint(infile, outfile, blocksize, windowsize, r, g, b)

Örnekler şeklinde yer almaktadır

;~ inpaint("gothic_in.png", "gothic_out.png")
;~ inpaint("starry_in.png", "starry_out.png")
;~ inpaint("scream_in.png", "scream_out.png")
;~ inpaint("mona_in.png", "mona_out.png")
;~ inpaint("maze_in.png", "maze_out.png")
;~ inpaint("checker_in.png", "checker_out.png")

sadece CTRL+ kullanarak çalıştırmak istediğiniz örneği yorumlayın Q.

Resmi Test Dosyaları

Bu algoritma her görüntü için ayarlanacak şekilde yapılmıştır . Bu nedenle, varsayılan değerler (ve ayrıca varsayılan maskeler) tamamen yetersizdir. Varsayılan değerler seçilmiştir, böylece her numune makul bir sürede işlenebilir. Düzensiz şekilli maskelerle ve daha iyi pencere boyutlarıyla oynamayı şiddetle tavsiye ederim. Büyütmek için resimlere tıklayın!

Dama tahtası

Gotik amerikan

Labirent

Mona Lisa

(korkunç maske)

Çığlık

Yıldızlı

Gerçek Dünyadan Örnekler

Bunların hepsi özel elle çizilmiş maskeler kullanır.

Dahil görmek istediğiniz başka ilginç resimleriniz varsa, yorum yapın.

EBII İyileştirmeleri

Çeşitli araştırmacılar tarafından yaratılmış, çeşitli EBII varyantları vardır. AnkurKumar Patel , çeşitli EBII gelişmeleriyle ilgili makale koleksiyonu [24] ile dikkatimi çekti .

Spesifik olarak, kağıt "örnek bir Tabanlı Görüntü inpainting için Geliştirilmiş Sağlam algoritması " [25] Öncelik değerleri ağırlığında iki geliştirmeleri belirtmektedir.

İyileştirme

Etkili değişiklik, algoritmanın 1. Adımında (yukarıya bakın) olup, aşağıdakileri kullanarak bu pikselin öncelik derecesi üzerindeki C (p) ve D (p) etkisini artırır:

Yukarıda verilen C ve D formüllerinde ve sırasıyla normalizasyon faktörü (örn., A = 255), izofot vektörü ve p noktasındaki öne dik bir birim vektördür .

Daha ileri,

Öncelik işlevi, C (p) düzenlenmiş güven teriminin ağırlık toplamı ve yeni D (p) veri terimlerinin tanımlarıdır . Α ayarlama katsayısı olduğunda, 0Rp (p) 'nin tatmin edici olması aşağıdaki gibi tanımlanır:

Α ve respectively sırasıyla güven ve veri terimlerinin bileşen ağırlıklarıdır. Α + β = 1 olduğuna dikkat edin .

Amaç puanlama

Yine de ilginç olan, bu yazının eğer EBII algoritmaları varsa performansı puanlamak için önerilen (ve basit!) Bir yöntem içermesidir. Bununla birlikte, bir tuz tuzu ile alın, bu, önerilen varyans yaklaşımının etkinliğini ve birkaç imge üzerindeki iyileştirmeyi doğrulamak için yazarlar tarafından seçilen bir yöntemdir.

Sonuç değerlendirmesi, geri yüklenen görüntü ile orijinal görüntü arasındaki PSNR (En Yüksek Sinyal-Gürültü Oranı [26] ) ile karşılaştırılarak yapılır . Genel olarak, PSNR değeri ne kadar yüksek olursa, onarılan görüntünün orijinaline benzerliği o kadar büyük olur. PSNR'yi hesaplamak için denklem aşağıdaki gibidir:

Bunlar, kullandıkları şaşırtıcı 2 (iki!) Gerçek dünya test görüntüsüdür:

Sonuç, makalenin kalitesi kadar hayal kırıklığı yaratıyor. Çok az gelişme gösterir. Buradaki en önemli şey, bu tür bir meydan okuma (ve diğer görüntü onarım zorlukları) için olası bir nesne puanlama yöntemidir:

+-------+---------------+----------+
| Image | EBII Original | Improved |
+-------+---------------+----------+
|     1 |       52.9556 |  53.7890 |
|     2 |       53.9098 |  53.8989 |
+-------+---------------+----------+

Meh.

Yapılacak araştırma

(EBII'ye özel)

a) Ön İşleme

Her şey, algoritmanın her şey için “sadece çalışması” gerektiği “Sihirli Silme” ilkesine dayanır. Bunun için saf çözümüm renk temelli bir büyütmedir (yukarıya bakın), ancak daha iyi yollar var. Pencere boyutunu otomatik olarak ayarlamak için tüm izlenebilir metinlerin geometrik ortalamasını tanıma ve pul boyutunu (aynı zamanda benim geliştirmeme) texel ve tam görüntü çözünürlüğüne bağlı hale getirmeyi düşünüyorum . Araştırma burada yapılmalı.

b) İşlem Sonrası

Orijinal yazarlar zaten akılda kalan tüm işlem sonrası filtrelerini harap etmek için çok iyi bir iş çıkardılar. Bugün, her zaman esrarengiz Mona Lisa'dan esinlenerek başka bir şey denedim (undergroundmonorail'e teşekkürler). Eğer alırsan sadece inpainted bölgeyi ve renk tüm garip bloklarına yeni bir maske uygulamak ve bir despeckling algoritması içine beslemek, bir neredeyse mükemmel sonuç ile kalacaksın. Bunu gelecekte biraz zaman keşfedebilirim.


[X] - A. Criminisi, P. Perez, K. Toyama
[1] - Örnekleme Tabanlı Boyamayla Obje Çıkarma - M. Ashikhmin. Doğal dokuların sentezlenmesi. Proc. ACM Symp. İnteraktif 3D Grafik Üzerine, s. 217-226, Araştırma Üçgeni Parkı, NC, Mar 2001.
[5] - M. Bertalmio, L. Vese, G. Sapiro ve S. Osher. Eşzamanlı yapı ve doku boyaması görünmesi, 2002
[6] - R. Bornard, E. Lecan, L. Laborelli ve JH. Chenot. Hareketsiz görüntülerde ve görüntü dizilerinde eksik veri düzeltmesi. ACM Multimedya, Fransa, Aralık 2002'de.
[7] - TF Chan ve J. Shen. Eğrilik kaynaklı difüzyonlarla (CDD) doku içermeyen boya. J. Visual Comm. Image Rep., 4 (12), 2001.
[8] - JS de Bonet. Doku görüntülerinin analizi ve sentezi için çoklu çözünürlük örnekleme prosedürü. Proc. ACM Konf. Zorunlu. Grafikler (SIGGRAPH), cilt 31, sayfa 361-368, 1997.
[9] - A. Efros ve WT Freeman. Doku sentezi ve transferi için görüntü kapitone. Proc. ACM Konf. Zorunlu. Grafikler (SİGGRAPH), sayfa 341-346, Eugene Fiume, Ağustos 2001.
[10] - A. Efros ve T. Leung. Parametrik olmayan örnekleme ile doku sentezi. Proc. ICCV, sayfa 1033-1038, Kerkyra, Yunanistan, Eylül 1999.
[11] - WT Freeman, EC Pasztor ve OT Carmichael. Düşük seviyeli görmeyi öğrenmek. Int. J. Computer Vision, 40 (1): 25–47, 2000.
[12] - D. Garber. Doku Analizi ve Doku Sentezi İçin Hesaplamalı Modeller. Doktora tezi, Üniv. Güney Kaliforniya, ABD, 1981.
[13] - P. Harrison. Karmaşık dokuların yeniden sentezi için hiyerarşik olmayan bir prosedür. Proc. Int. Konf. Orta Avrupa Comp. Grafikler, Visua. ve Comp. Vision, Plzen, Çek Cumhuriyeti, Şubat 2001.
[14] - DJ Heeger ve JR Bergen. Piramit tabanlı doku analizi / sentezi. Proc. ACM Konf. Zorunlu. Grafikler (SIGGRAPH), cilt 29, sayfa 229-233, Los Angeles, CA, 1995.
[15] - A. Hertzmann, C. Jacobs, N. Oliver, B. Curless ve D. Salesin. Görüntü analojileri. Proc. ACM Konf. Zorunlu. Grafik (SIGGRAPH), Eugene Fiume, Ağustos 2001.
[16] - H. İgehy ve L. Pereira. Doku sentezi yoluyla görüntü değiştirme. Proc. Int. Konf. Görüntü İşleme, s. III: 186-190, 1997.
[17] - G. Kanizsa. Vizyonda Organizasyon. Praeger, New York, 1979.
[19] - L. Liang, C. Liu, Y.-Q. Xu, B. Guo ve H.-Y. Shum. Yama bazlı örneklemeyle gerçek zamanlı doku sentezi. Grafiklerdeki ACM İşlemlerinde, 2001.
[22] - L.-W. Wey ve M. Levoy. Ağaç yapılı vektör nicelemesi kullanılarak hızlı doku sentezi. Proc. ACM Konf. Zorunlu. Grafik (SIGGRAPH), 2000.
[23] - A. Zalesny, V. Ferrari, G. Caenen ve L. van Gool. Paralel kompozit doku sentezi. Doku 2002 atölye -, Kopenhag, Danimarka (ECCV02 ile birlikte), Haziran 2002
[24] - AkurKumar Patel, Gujarat Teknoloji Üniversitesi, Bilgisayar Bilimleri ve Mühendisliği
[25] - Exemplar Tabanlı Görüntü inpainting İçin Geliştirilmiş Sağlam Algoritma
[26] - Vikipedi, Zirve-Sinyal-Gürültü Oranı


30
Bu harika . Yıldızlı Gece çok güzel. Yine de, o Mona Lisa ...
Hannes Karppila

8
İlk önce "aman tanrım bu inanılmaz" diyeyim. İkincisi: Buradaki başka bir soruda "Mona Lisa'nın bir SCP olayı" olduğunu zaten yorumladım, ama bu baykuş SCP wiki'de görünebilecek bir şeye benziyor.
undergroundmonorail,

3
Alıntılanan paragraflara alıntı bloku yapılabilir mi?
trichoplax

1
@trichoplax Neredeyse her cümleyle ilgili küçük değişiklikler var, bunlar tam alıntı değil. Algoritma tanımını org ile aynı şekilde ele alın. kağıt, değişiklik veya kod yazdığı zamanlar hariç. Artık biçimlendirmeyi karıştırmak istemiyorum :)
mınxomaτ

2
Rüyalarımda çok dikkatli bir şeye bakmaya çalıştığımda, bazen işler tam olarak böyle oluyor.
jimmy23013

45

Matlab

Bu basit bir enterpolasyon yaklaşımıdır. Fikir ilk önce yamanın her iki tarafındakileri yansıtıyor. Sonra bu ayna görüntüsü pikselleri, karşılık gelen kenara ne kadar yakın olduklarıyla enterpolasyon yapar:

En zor kısım, güzel bir enterpolasyon ağırlıkları bulmaktı. Etrafta biraz çaldıktan sonra, aynaya çarptığımız nokta dışında tüm kenarlarda sıfır olan rasyonel bir işlev gördüm. Bu daha sonra bazı yumuşatma için üçüncü derece bir polinom tarafından dönüştürülür:

Bu basit yaklaşım "doğal" görüntülerde şaşırtıcı derecede iyi sonuç veriyor, ancak keskin kenarlarla karşılaştığınız anda oyun bitti. Gelen amerikan gotik örneğin yukarı güzel oldukça güzel görünmesini sağlar piksel ızgarasına sahip saman çatal hattının ani ama çok daha kötü aksi olurdu.

Yani burada sonuçlar:

Ve nihayet, kod:

imgfile= 'filename.png';
maskfile = [imgfile(1:end-4),'_mask.png'];
img = double(imread(imgfile));
mask = rgb2gray(imread(maskfile));
%% read mask
xmin = find(sum(mask,1),1,'first');
xmax = find(sum(mask,1),1,'last');
ymin = find(sum(mask,2),1,'first');
ymax = find(sum(mask,2),1,'last');
%% weight transformation functiosn
third = @(x)-2* x.^3 + 3* x.^2;
f=@(x)third(x);
w=@(x,y)y.*(x-1).*(y-1)./( (x+y).*(x+1-y));

for x=xmin:xmax
    for y=ymin:ymax
        %Left Right Up Down;
        P = [img(y,xmin-(x-xmin)-1,:);img(y,xmax+(xmax-x)+1,:);img(ymin-(y-ymin)-1,x,:);img(ymax+(ymax-y)+1,x,:)];
        % normalize coordinates
        rx = (x-xmin)/(xmax-xmin); 
        ry = (y-ymin)/(ymax-ymin);
        % calculate the weights
        W = [w(rx,ry),w(1-rx,ry),w(ry,rx),w(1-ry,rx)]';
        W = f(W);
        W(isnan(W))=1;
        img(y,x,:) = sum(bsxfun(@times,P,W),1)/sum(W); 
    end
end
imshow(img/255);
imwrite(img/255,[imgfile(1:end-4),'_out.png']);

10
Mona Lisa beni korkutuyor.
Andras Deak

46
Ḿ̳̜͇͓͠o̢̎̓̀ǹ̰͎̣͙a̤̩̖̞̝ͧ̈ͤͤ ̣̖̠̮̘̹̠̾̇ͣL͉̻̭͌i̛̥͕̱͋͌ş̠͔̏̋̀ạ̫͕͎ͨͮͪ̐͡ͅ
mınxomaτ

8
Mona Lisa bazı SCP bok O
undergroundmonorail

1
Damalı görüntü IMHO gerçekten harika görünüyor.
ETHProductions

1
Bununla kendi mücadeleni kazanırsan şaşırmam. Bu gerçekten güzel bir çözüm.
Alex A. 18

25

Mathematica

Bu, Mathematica'nın Inpaintişlevini kullanır . Mathematica'nın kendisi tüm ağır yükleri kaldırdığından, bu bir topluluk wiki'sidir.

inPaint(aşağıda) basit bir uyarlamadır Inpaint. Renkli resimler / fotoğraflar için, varsayılan "TextureSynthesis" ayarını kullanır. Resmin siyah beyaz olduğunu tespit ederse (resmin resim verileri resmin ikili biçiminin resim verileriyle aynı olduğu için), ardından resmi binarize eder ve "TotalVariation" yamasını uygular. IfFıkra ya uygular Binarizeveya Identityresme. ( Identityİşlev, argümanını değiştirmeden döndürür.)

inPaint[picture_, mask_] :=  
 If[bw = ImageData@Rasterize[Binarize[picture]] == ImageData[picture], Binarize, Identity]@
  Inpaint[picture, mask, Method -> If[bw, "TotalVariation", "TextureSynthesis"]]

Görüntü ve maske argüman olarak girilir inPaint. Partitionve Gridsadece biçimlendirme amaçlıdır.

giriş

Çıktılar yamalandı. Sonrasında görüntülerin rötuşlanması yoktu inPaint.

çıktı


4
Bu bir tesadüf olabilir, ama labirentin performansına hayran kaldım!
kusur,

1
@flawr Sadece bu çözümle uğraşmak için böyle bir şeye fırlatırdım ;) (Kim bilir? Bu siyah beyazlar gerçekten şaşırıyor.)
Andras Deak

17
Bunun bir topluluk wiki olması gerektiğini düşünmüyorum.
Dennis

Lawr, Evet, Inpaintsiyah beyaz görüntünün tamamında simetri aramak gibi görünüyor. - DavidC 9 saat önce
DavidC

Siyah-beyaz algoritmanın hiçbir yerde keçi feda etmeyi içermediğinden emin misin ? Nasıl --- Dünyada --- cehennem hepsi maskeli ise, görüntünün merkezi yapısını tahmin ediyor mu?
Andras Deak

18

Python 2 ve PIL

Bu program, yerel görüntü bölgesinden renkler, dokular ve gölgeleme kullanan yedek pikseller oluşturmak için Kuzey, Güney, Doğu ve Batı bölgelerinin kopyalarını harmanlamaktadır.

Örnek çıktı:

Kod ilk önce yamanın sınırlayıcı kutusunu bulur. Daha sonra üretilecek olan her piksel için, 4 çevreleyen bölgenin ağırlıklı toplamına dayanarak her bir kanalın (RGB) rengini hesaplar.

import sys
from PIL import Image

infile, maskfile, outfile = sys.argv[1:4]
imageobj = Image.open(infile)
maskobj = Image.open(maskfile)
image = imageobj.load()
mask = maskobj.load()

assert imageobj.size == maskobj.size
W, H = imageobj.size
pixels = [(x,y) for x in range(W) for y in range(H)]
whitepart = [xy for xy in pixels if sum(mask[xy]) > 230*3]
xmin = min(x for x,y in whitepart)
xmax = max(x for x,y in whitepart)
ymin = min(y for x,y in whitepart)
ymax = max(y for x,y in whitepart)
xspan = xmax - xmin + 1
yspan = ymax - ymin + 1

def mkcolor(channel):
    value = image[(xmin-dx, y)][channel] * 0.5*(xspan - dx)/xspan
    value += image[(xmax+1 + xspan - dx, y)][channel] * 0.5*dx/xspan
    value += image[(x, ymin-dy)][channel] * 0.5*(yspan - dy)/yspan
    value += image[(x, ymax+1 + yspan - dy)][channel] * 0.5*dy/yspan
    return int(value)

for dx in range(xspan):
    for dy in range(yspan):
        x = xmin + dx
        y = ymin + dy
        image[(x, y)] = (mkcolor(0), mkcolor(1), mkcolor(2))

imageobj.save(outfile)

3
Bu Mona Lisa da korkutucu! Bu mücadeledeki tüm Mona Lisas'lar korkutucu olmaya mahkum mu?
undergroundmonorail,

@undergroundmonorail Sanırım bilgisayar kaynaklı kaza yüzleri esrarengiz vadinin derinliklerinden geliyor .
Andras Deak

PIL'i nereden aldın?
Elliot A.

@ElliotA. Anladığım kadarıyla PIL uygun ölü, ama açık kaynak ve bu yüzden "Yastık" adı altında yaşıyor. "Python yastık" google bulursanız onu bulmalısınız.
undergroundmonorail,

13

Python 3, PIL

Bu program sobel operatörünü kullanır ve buna bağlı olarak resmin üzerine çizgiler çizer.

Sobel operatörü her bir kenarın açısını bulur, bu nedenle bilinmeyen bölgeye giren herhangi bir kenar devam etmelidir.

from PIL import Image, ImageFilter, ImageDraw
import time
im=Image.open('2.png')
im1=Image.open('2 map.png')
a=list(im.getdata())
b=list(im1.getdata())
size=list(im.size)
'''
def dist(a,b):
    d=0
    for x in range(0,3):
        d+=(a[x]-b[x])**2
    return(d**0.5)
#'''
C=[]
d=[]
y=[]
for x in range(0,len(a)):
    if(b[x][0]==255):
        C.append((0,0,0))
    else:
        y=(a[x][0],a[x][1],a[x][2])
        C.append(y)
im1.putdata(C)
k=(-1,0,1,-2,0,2,-1,0,1)
k1=(-1,-2,-1,0,0,0,1,2,1)
ix=im.filter(ImageFilter.Kernel((3,3),k,1,128))
iy=im.filter(ImageFilter.Kernel((3,3),k1,1,128))
ix1=list(ix.getdata())
iy1=list(iy.getdata())
d=[]
im2=Image.new('RGB',size)
draw=ImageDraw.Draw(im2)
c=list(C)
Length=0
for L in range(100,0,-10):
    for x in range(0,size[0]):
        for y in range(0,size[1]):
            n=x+(size[0]*y)
            if(c[n]!=(0,0,0)):
                w=(((iy1[n][0]+iy1[n][1]+iy1[n][2])//3)-128)
                z=(((ix1[n][0]+ix1[n][1]+ix1[n][2])//3)-128)
                Length=(w**2+z**2)**0.5
                if Length==0:
                    w+=1
                    z+=1
                Length=(w**2+z**2)**0.5
                w/=(Length/L)
                z/=(Length/L)
                w=int(w)
                z=int(z)
                draw.line(((x,y,w+x,z+y)),c[n])

d=list(im2.getdata())
S=[]
d1=[]
A=d[0]
for x in range(0,size[0]):
    for y in range(0,size[1]):
        n=y+(size[1]*x)
        nx=y+(size[1]*x)-1
        ny=y+(size[1]*x)-size[0]
        if d[n]==(0,0,0):
            S=[0,0,0]
            for z in range(0,3):
                S[z]=(d[nx][z]+d[ny][z])//2
            #print(S)
            d1.append(tuple(S))
        else:
            d1.append(tuple(d[n]))
d=list(d1)
im2.putdata(d)
#im2=im2.filter(ImageFilter.GaussianBlur(radius=0.5))
d=im2.getdata()
f=[]
#'''
for v in range(0,len(a)):
    if(b[v][0]*b[v][1]*b[v][2]!=0):
        f.append(d[v])
    else:
        f.append(C[v])
#'''
im1.putdata(f)
im1.save('pic.png')

Bu arada, işte örnek görüntüler.

görüntü tanımını buraya girin

görüntü tanımını buraya girin

görüntü tanımını buraya girin

Mona Lisa Mona Lisa Ḿ͠oǹ̰͎̣a ̾̇Lisa Ḿ͠o̢̎̓̀ǹ̰͎̣aͧ̈ͤ ̣̖̠̮̘̹̠̾̇ͣLisa Ḿ̳̜͇͓͠o̢̎̓̀ǹ̰͎̣͙a̤̩̖̞̝ͧ̈ͤͤ ̣̖̠̮̘̹̠̾̇ͣL͉̻̭͌i̛̥͕̱͋͌ş̠͔̏̋̀ạ̫͕͎ͨͮͪ̐͡ͅ

görüntü tanımını buraya girin Yukarıdaki görüntüdeki alan bir kaktüs kadar pürüzsüzdür

Sabit renk ile çok iyi değil.

görüntü tanımını buraya girin

görüntü tanımını buraya girin


1
Oh, ve s / b test durumlarını ekler misiniz?
kusur

2
Starry Night 1'de çok iyi görünüyor.
SuperJedi224

1
Vay, bu şimdi inanılmaz görünüyor! Yamalar hala göze çarpıyor ama harika bir fikir! Şimdiye kadar favorilerim =)
flawr

8
+1 "Mona Lisa Mona Lisa ̾̇oǹ̰͎̣a ̾̇Lisa Ḿ͠oisaaͧ̈ͤ isaLisa Ḿ̳̜͇͓͠o̢̎̓̀ǹ̰͎̣͙a̤̩̖̞̝ͧ̈ͤͤ ̣̖̠̮̘̹̠̾̇ͣL͉̻̭͌i̛̥͕̱͋͌ş̠͔̏̋̀ạ̫͕͎ͨͮͪ̐͡ͅ"
mbomb007

2
IMO, "en korkutucu Mona Lisa" yarışmasını kazandın. 0_o
DLosc

8

Python 2

Boşluğun hemen dışındaki piksellerin değerlerini kullanarak düzeltme eki oluşturan basit python betiği. Piksel satır ve sütununun sonundaki renk değerlerini alır ve bu piksellere olan uzaklığı kullanarak ağırlıklı ortalamaları hesaplar.

Çıktı çok hoş değil, ama sanat .

img1 img2 img3 img4 img5 img6

Ve sonra, kod:

IMGN = "6"

IMGFILE = "images/img%s.png" % (IMGN,)
MASKFILE = "images/img%s_mask.png" % (IMGN,)

BLUR = 5


def getp(img,pos):
    return img.get_at(pos)[:3]
def setp(img,pos,color):
    img.set_at(pos, map(int, color))

def pixelavg(L):
    return map(int, [sum([i[q] for i in L])/float(len(L)) for q in [0,1,2]])
def pixelavg_weighted(L, WL):   # note: "inverse" weights. More weight => less weight
    # colors [sum, max]
    color_data = [[0, 0], [0, 0], [0, 0]]
    for color,weight in zip(L, WL):
        for i in [0, 1, 2]: # r,g,b
            color_data[i][0] += inv_w_approx(weight) * color[i]
            color_data[i][1] += inv_w_approx(weight) * 255
    return [255*(float(s)/m) for s,m in color_data]
def inv_w_approx(x):
    return (1.0/(x+1e-10))

import pygame
image = pygame.image.load(IMGFILE)
mask = pygame.image.load(MASKFILE)

size = image.get_size()
assert(size == mask.get_size())

# get square from mask
min_pos = None
max_pos = [0, 0]
for x in range(size[0]):
    for y in range(size[1]):
        if getp(mask, [x, y]) == (255, 255, 255):
            if min_pos == None:
                min_pos = [x, y]
            max_pos = [x, y]
if not min_pos:
    exit("Error: no mask found.")
# patch area info
patch_position = min_pos[:]
patch_size = [max_pos[0]-min_pos[0], max_pos[1]-min_pos[1]]

# remove pixels from orginal image (fill black)
for dx in range(patch_size[0]):
    for dy in range(patch_size[1]):
        setp(image, [patch_position[0]+dx, patch_position[1]+dy], [0, 0, 0])

# create patch
patch = pygame.Surface(patch_size)

# take pixels around the patch
top = [getp(image, [patch_position[0]+dx, patch_position[1]-1]) for dx in range(patch_size[0])]
bottom = [getp(image, [patch_position[0]+dx, patch_position[1]+patch_size[1]+1]) for dx in range(patch_size[0])]
left = [getp(image, [patch_position[0]-1, patch_position[1]+dy]) for dy in range(patch_size[1])]
right = [getp(image, [patch_position[0]+patch_size[0]+1, patch_position[1]+dy]) for dy in range(patch_size[1])]

cpixels = top+left+right+bottom

# set area to average color around it
average = [sum([q[i] for q in cpixels])/float(len(cpixels)) for i in [0, 1, 2]]

for dx in range(patch_size[0]):
    for dy in range(patch_size[1]):
        setp(patch, [dx, dy], average)

# create new pixels
for dx in range(patch_size[0]):
    for dy in range(patch_size[1]):
        setp(patch, [dx, dy], pixelavg_weighted([top[dx], bottom[dx], left[dy], right[dy]], [dy, patch_size[1]-dy, dx, patch_size[0]-dx]))

# apply patch
for dx in range(patch_size[0]):
    for dy in range(patch_size[1]):
        setp(image, [patch_position[0]+dx, patch_position[1]+dy], getp(patch, [dx, dy]))

# blur patch?
for r in range(BLUR):
    for dx in range(patch_size[0]):
        for dy in range(patch_size[1]):
            around = []
            for ddx in [-1,0,1]:
                for ddy in [-1,0,1]:
                    around.append(getp(image, [patch_position[0]+dx+ddx, patch_position[1]+dy+ddy]))
            setp(patch, [dx, dy], pixelavg(around))

    # apply blurred patch
    for dx in range(patch_size[0]):
        for dy in range(patch_size[1]):
            setp(image, [patch_position[0]+dx, patch_position[1]+dy], getp(patch, [dx, dy]))

# save result
pygame.image.save(image, "result.png")

Şu anda bu yatay / dikey çizgileri görüyorsanız, belki başka yönleri de ekleyerek iyileştirebilirsiniz!
kusur

Aslında denedim ama iyi sonuçlar alamadım, bu yüzden sadece görüntüyü bulanıklaştırmaya karar verdim: D
Hannes Karppila

19
Son olarak, bir Mona Lisa gelmez ölüm beni korkutmak, ancak bunun yerine bir tutuklandı katil gibi görünüyor.
Andras Deak

6

Mathematica

Inpaint

Sadece Mathematica'nın bu görevi yerine getiren yerleşik bir işlevi var ve tam olarak kastediyorum :

Inpaint[image, region]

  • içindeki parçaları imagesıfır olmayan öğelere karşılık gelen rötuşlar region.

Varsayılan olarak, resimlerde iyi sonuçlar veren, ancak labirent ve dama tahtası için kötü sonuçlar veren "rastgele örneklemeyi kullanan" en uygun doku sentezi yöntemini "kullanır:

görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin

Ayarlarla uğraşmak beni tüm görüntülerde kaliteyi artırmamı sağladı, bu yüzden sadece varsayılanları kullandım (baytları kurtarmak için — bu codegolf.sesonuçta!).


23
" Öyle ki, Mathematica'nın yerleşik bir işlevi var " ... sürpriz, sürpriz;)
Andras Deak

Labirent ve kontrol panosu için "TotalVariation" yöntemini birlikte kullanmak daha iyidir Binarize(gri lekeleri gidermek için). Bunu dene: methods = {"TextureSynthesis", "Diffusion", "FastMarching", "NavierStokes", "TotalVariation"};g[pic_, mask_] := Join[{Labeled[Framed@pic, "Original"]}, Labeled[ Binarize@Inpaint[pic, mask, Method -> #], #] & /@ methods]
DavidC

@DavidC Diğer yöntemleri denedim, ama resimlerde sadece TextureSynthesisiyi görünüyor; ve her test durumu için ayarlarımızı değiştirmemize izin verildiğini sanmıyorum. (Yapabilirsek, o zaman eksik kısmı
önemsizce

Labirent ve dama tahtası sonuçları beni gerçekten şaşırtıyor. Mathematica’nın kayıp bölgeyi yeniden inşası neden bu kadar düzensiz ve asimetrik?
David Zhang,

Bu, görüntünün siyah beyaz olup olmadığını otomatik olarak algılar ve uygun ayarları yapar (ikili dosyalar ve "TotalVariation" yöntemi). inPaint[picture_, mask_] := If[bw = ImageData@Rasterize[Binarize[picture]] == ImageData[picture], Binarize, Identity]@ Inpaint[picture, mask, Method -> If[bw, "TotalVariation", "TextureSynthesis"]]
DavidC,

5

Python3

Bu cevap Ulyanov ve arkadaşlarının "Deep Image Prior" adlı makalesinde yer almaktadır . (CVPR 2018) Bu yazıda, görüntü işleme için sinir ağlarının iyi performans göstermesinin, doğal bir görüntünün nasıl görünmesi gerektiği konusundaki fikrimizi ("önceki" dağıtım) yakından yansıttığı fikrini araştırdılar.

Herhangi bir veri üzerinde eğitim almadan sadece verilen görüntüyü kullanan gürültü ve eser çıkarma işleminin yanı sıra boyamalar için kullanılabilecek bir yöntem önerdiler. Gerçek konsept oldukça basittir: Ağ, yalnızca belirli bir maskenin dışındaki erroları cezalandırmak suretiyle istenen görüntüyü (girdi olarak sabit rastgele bir ses için) çıkarmak için eğitilir. Gürültüyü gidermek istiyorsanız, hiçbir şeyi maskelemeniz gerekmez, fakat sadece antrenman için erken durun.

Boyamalar için, boyamak istediğiniz parçayı maskeleyin ve yakınlaşmaya kadar çalışın. Kesinlikle son teknoloji ürünü bir ürün değil, ama hala fikrinin sadeliği ve dikkat çekici performansı nedeniyle denemek ve buraya göndermek istedim. Deneylerimde, daha büyük yamaların boyamasındaki durum o kadar iyi sonuç vermedi, ancak daha küçük bölümler için sonuçlar çok daha ikna edici olabilir.

Bunu , github'daki jaxony'den popüler U-Net mimarisini kullanarak uyguladım . Görüntülerin eğitimi ve işlenmesi için kod aşağıda bulunabilir.

Eğitim

Bu, eğitim sürecinin bir görselleştirmesidir. Her kare, belirli sayıda yinelemenin halidir:

Örnekler

kod

Bir cpu üzerinde bu işlemin yalnızca tek bir görüntü için çalışması saatlerce sürebilirken, iyi bir cuda özellikli gpu'nun çok daha az zaman alabileceğini unutmayın.

import torch
import numpy as np
unet = __import__('unet-pytorch')
import PIL.ImageOps
#specify device (cpu/cuda)
device = "cpu"
#specify file and size
file = 'mona'
size = 512 #pad to this size (no smaller than original image), must be divisible by 2^5
img_pil = PIL.Image.open(file +'.png').convert('RGB')
mask_pil = PIL.Image.open(file +'-mask.png').convert('RGB')

net = unet.UNet(num_classes=3, in_channels=32, depth=6, start_filts=64).to(device)
h,w = img_pil.size
pad = (0, 0, size - h, size - w)
img = PIL.ImageOps.expand(img_pil, border=pad)
img = torch.Tensor(np.array(img).transpose([2, 0, 1])[None, :, :, :].astype(np.double)).to(device)
mask = PIL.ImageOps.expand(mask_pil, border=pad)
mask = torch.Tensor((np.array(mask)==0).transpose([2, 0, 1])[None, 0:3, :, :].astype(np.double)).to(device)
mean = img.mean()
std = img.std()
img = (img - mean)/std
optimizer = torch.optim.Adam(net.parameters(), lr=0.0001)
criterion = torch.nn.MSELoss()
input = torch.rand((1, 32, size, size)).to(device)
for it in range(5000):
    if it == 1000:
        optimizer.param_groups[0]['lr'] = 0.00003
    out = net(input)
    loss = criterion(out * mask, img * mask)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
out = out.detach().cpu().numpy()[0].transpose([1,2,0])*std.item() + mean.item()
out = np.clip(out, 0, 255).astype(np.uint8)[0:w, 0:h, :]
mask_np = (np.array(mask_pil) > 0).astype(np.uint8)
img_np = np.array(img_pil)
inpaint = (img_np * (1-mask_np) + mask_np * out).astype(np.uint8)
PIL.Image.fromarray(inpaint).save('./{}_inpainted.png'.format(file))

Image Prior, U-Nets'ten farklı bir şey kullanıyor mu? daha iyi sonuçlar alacaklar gibi görünüyor
ASCII sadece

Ayrıca, Deep Image Prior'in kodunu denediniz mi
ASCII-sadece

@ Yalnızca ASCII - Makalede gerçekten U-Net kullandıklarını belirtirler, fakat kullandıkları parametreleri tam olarak bulamıyorum. Daha büyük kapasiteli bir ağ kullanmış olabilirler. Sadece çok sınırlı bir güce sahip bir bilgisayarım vardı. Bu yüzden hala belleğe uygun ve eğitilmesi çok uzun sürmeyen parametreleri seçmek zorunda kaldım. Tam olarak ne kadar sürdüğünden emin değilim ama kullandığım bilgisayarda (sadece bir CPU ile) bu resimler birkaç gün sürüyor. (Yedek cuda etkin bir
GPU'nuz varsa

Ayrıca, örneğin, ilk birkaç görüntüyü son ikiyle karşılaştırdığınızda (dikdörtgen maskeler kullanmıyorsanız) dikdörtgen maskelere sahip olan ağın tasarımı nedeniyle ideal maskelerin (ve daha küçük maskelerin de muhtemelen daha iyi görüneceğini) ideal olmadığını düşünüyorum. .
kusur

4

OpenCV ile Python

OpenCV inpaint adlı bir işleve sahiptir. Kullanılan iki tür boyalama vardır, Hızlı Yürüyüş Metodu'nu kullanacağım. Belgelere göre, algoritma şöyle çalışır:

Resimde boyanacak bir bölge düşünün. Algoritma, bu bölgenin sınırından başlar ve önce sınırdaki her şeyi aşamalı olarak dolduran bölgeye girer. Boyanacak semtte piksel etrafında küçük bir mahalle alır. Bu piksel, çevrede bilinen tüm piksellerin normalize ağırlıklı toplamı ile değiştirilir. Ağırlıkları seçmek önemli bir konudur. Sınırın normaline yakın, noktaya yakın yatan ve sınır hatlarında yatan piksellere daha fazla ağırlık verilir. Bir piksel boyandıktan sonra, Hızlı Yürüyüş Metodu kullanılarak bir sonraki en yakın piksele gider. FMM, bilinen piksellerin yakınındaki bu piksellerin ilk olarak boyanmasını sağlar, böylece sadece manuel bir sezgisel işlem gibi çalışır.

İşte kod *:

import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('gothic.jpg')
b,g,r = cv2.split(img)
img2 = cv2.merge([r,g,b])
mask = cv2.imread('mask.jpg',0)
dst = cv2.inpaint(img2,mask,3,cv2.INPAINT_TELEA)
(h, w) = dst.shape[:2]
center = (w / 2, h / 2)
# rotate the image by 180 degrees
M = cv2.getRotationMatrix2D(center, 180, 1.0)
rotated = cv2.warpAffine(dst, M, (w, h))
plt.imshow(rotated)

Çizim sebeplerinden dolayı BGR'yi RGB'ye nasıl dönüştürdüğüme dikkat edin. Ayrıca, onu döndürürüm. Sonuçlar burada:

Gotik

yıldızlı Gece çığlık başka bir ürpertici mona lisa!

Mona Lisa döner!

satır 1

denetleyicisi

Gördüğünüz gibi, iki renkli olanla en iyisi değilim.


Mona Lisa bir facelift aldı
Conor O'Brien,

3

Java

Renk ortalama yaklaşımı. Muhtemelen geliştirilebilir.

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Scanner;

import javax.imageio.ImageIO;


public class ImagePatcher{
    public static void main(String[]args) throws Exception{
        Scanner in=new Scanner(System.in);
        int white=Color.WHITE.getRGB();
        int black=Color.BLACK.getRGB();
        BufferedImage image=ImageIO.read(new File(in.nextLine())),mask=ImageIO.read(new File(in.nextLine()));
        assert(image.getWidth()==mask.getWidth()&&image.getHeight()==mask.getHeight());
        boolean bool=true;
        while(bool){
            bool=false;
        for(int x=0;x<image.getWidth();x+=2){
            for(int y=0;y<image.getHeight();y+=2){
                if(mask.getRGB(x,y)!=white)continue;
                int r=0,g=0,b=0,n=0;
                for(int dx=-1;dx<=1;dx++){
                    if(x+dx<0)continue;
                    if(x+dx>=image.getWidth())continue;
                    for(int dy=-1;dy<=1;dy++){
                        if(y+dy<0)continue;
                        if(y+dy>=image.getHeight())continue;
                        if(mask.getRGB(x+dx,y+dy)==white)continue;
                        Color c=new Color(image.getRGB(x+dx,y+dy));
                        r+=c.getRed();
                        g+=c.getGreen();
                        b+=c.getBlue();
                        n++;
                    }
                }
                if(n==0){bool=true;continue;}
                Color c=n>0?new Color(r/n,g/n,b/n):new Color(100,100,100);
                image.setRGB(x,y,c.getRGB());
                mask.setRGB(x, y, black);
            }           
        }
        for(int x=0;x<image.getWidth();x+=2){
            for(int y=1;y<image.getHeight();y+=2){
                if(mask.getRGB(x,y)!=white)continue;
                int r=0,g=0,b=0,n=0;
                for(int dx=-1;dx<=1;dx++){
                    if(x+dx<0)continue;
                    if(x+dx>=image.getWidth())continue;
                    for(int dy=-1;dy<=1;dy++){
                        if(y+dy<0)continue;
                        if(y+dy>=image.getHeight())continue;
                        if(mask.getRGB(x+dx,y+dy)==white)continue;
                        Color c=new Color(image.getRGB(x+dx,y+dy));
                        r+=c.getRed();
                        g+=c.getGreen();
                        b+=c.getBlue();
                        n++;
                    }
                }
                if(n==0){bool=true;continue;}
                Color c=n>0?new Color(r/n,g/n,b/n):new Color(100,100,100);
                image.setRGB(x,y,c.getRGB());
                mask.setRGB(x, y, black);
            }
        }
        for(int x=1;x<image.getWidth();x+=2){
            for(int y=0;y<image.getHeight();y+=2){
                if(mask.getRGB(x,y)!=white)continue;
                int r=0,g=0,b=0,n=0;
                for(int dx=-1;dx<=1;dx++){
                    if(x+dx<0)continue;
                    if(x+dx>=image.getWidth())continue;
                    for(int dy=-1;dy<=1;dy++){
                        if(y+dy<0)continue;
                        if(y+dy>=image.getHeight())continue;
                        if(mask.getRGB(x+dx,y+dy)==white)continue;
                        Color c=new Color(image.getRGB(x+dx,y+dy));
                        r+=c.getRed();
                        g+=c.getGreen();
                        b+=c.getBlue();
                        n++;
                    }
                }
                if(n==0){bool=true;continue;}
                Color c=n>0?new Color(r/n,g/n,b/n):new Color(100,100,100);
                image.setRGB(x,y,c.getRGB());
                mask.setRGB(x, y, black);
            }           
        }
        for(int x=1;x<image.getWidth();x+=2){
            for(int y=1;y<image.getHeight();y+=2){
                if(mask.getRGB(x,y)!=white)continue;
                int r=0,g=0,b=0,n=0;
                for(int dx=-1;dx<=1;dx++){
                    if(x+dx<0)continue;
                    if(x+dx>=image.getWidth())continue;
                    for(int dy=-1;dy<=1;dy++){
                        if(y+dy<0)continue;
                        if(y+dy>=image.getHeight())continue;
                        if(mask.getRGB(x+dx,y+dy)==white)continue;
                        Color c=new Color(image.getRGB(x+dx,y+dy));
                        r+=c.getRed();
                        g+=c.getGreen();
                        b+=c.getBlue();
                        n++;
                    }
                }
                if(n==0){bool=true;continue;}
                Color c=n>0?new Color(r/n,g/n,b/n):new Color(100,100,100);
                image.setRGB(x,y,c.getRGB());
                mask.setRGB(x, y, black);
            }
        }
        };
        ImageIO.write(image, "png", new File("output.png"));
    }
}

Sonuçlar:

görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin görüntü tanımını buraya girin


2
Neden her zaman bu özel açıda çizgiler alıyorsunuz? Sol üst köşeler nispeten iyi eşleşiyor gibi gözükse de, sağ alt bölüm hiç uyuşmuyor.
kusur

Bölgede yinelediğim şekilde yapması gerektiğini düşünüyorum. Muhtemelen sonunda değiştiririm.
SuperJedi224,

Her zaman yamuk gibi gözüküyor.
ericw31415

@ ericw31415 Bu yineleme düzeninin bir eseridir.
SuperJedi224
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.