Görüntüden Beyaz Arka Planı Kaldırma ve Şeffaf Yapma


82

Mathematica'da şunları yapmaya çalışıyoruz - RMagick beyaz arka planı görüntüden kaldırıp şeffaf hale getir .

Ancak gerçek fotoğraflarda kötü görünmeye başlar (görüntünün etrafında bir hale olması gibi).

Şimdiye kadar denediklerimiz:

unground0[img_] := With[{mask = ChanVeseBinarize[img, TargetColor->{1.,1.,1.}]},
  Rasterize[SetAlphaChannel[img, ImageApply[1-#&, mask]], Background->None]]]

İşte bunun ne işe yaradığına dair bir örnek.

Gerçek görüntü:

gerçek görüntü

Arka planı olmayan beyaz arka plana sahip görüntü (veya burada tanıtım amacıyla pembe bir arka plan):

şeffaf arka plana sahip görüntü - halo sorununu belirgin hale getirmek için aslında burada pembe bir arka plan

O halodan kurtulmak için herhangi bir fikrin var mı? LevelPenalty gibi şeyleri ince ayarlayarak, yalnızca görüntünün bir kısmını kaybetme pahasına halenin kaybolmasını sağlayabilirim.

DÜZENLEME: Öyleyse, ödül için çözümleri karşılaştırabilirim, lütfen çözümünüzü yukarıdaki gibi yapılandırın, yani bir görüntüyü alan ve şeffaf bir arka plana sahip bir görüntü döndüren kendi kendine yeten bir işlev olan yuvarlak olmayan bir şey.


1
Şimdiye kadarki yardımlarınız için çok teşekkürler, millet! Stackoverflow bir tane eklememe izin verir vermez buna büyük ödül geliyor. Ve kurucuların ifade ettiği yığın aşımı ruhuna göre, cevabınızı kesin hale getirmek için birbirinizden çalmakta özgür olmalısınız!
Dreeves

3
İlk 500 ödül ve ardından "Mümkünse onu geliştirmek için hepinizi özgürce birbirinizden ödünç almaya teşvik ediyorum!" - köpek dövüşü istiyorsun, değil mi?
Bay Sihirbaz

@ Bay Sihirbaz, :) Kurucuların (Jeff ve Joel) bunun cesaretlendirildiğini en başından söylediklerini uydurmuyorum. Buradaki fikir, en iyi cevabın gerçekten eksiksiz ve kesin olması. (Ve tabii ki ben de bu durumda olduğu gibi gizli niyetlerimiz var!)
dreeves

2
Aşırı meraklılar için, bu IKEA'nın "FREDRIK" bilgisayar çalışma istasyonu: ikea.com/us/en/catalog/products/60111123
Arnoud Buzing

1
@dreeves, kullandığım tineye.com .
Arnoud Buzing

Yanıtlar:


45

Belki ihtiyacınız olan kenar kalitesine bağlı olarak:

img = Import@"http://i.stack.imgur.com/k7E1F.png";
mask = ChanVeseBinarize[img, TargetColor -> {1., 1., 1.}, "LengthPenalty" -> 10]
mask1 = Blur[Erosion[ColorNegate[mask], 2], 5]
Rasterize[SetAlphaChannel[img, mask1], Background -> None]

görüntü açıklamasını buraya girin

Düzenle

Stealing a bit from @Szabolcs

img2 = Import@"http://i.stack.imgur.com/k7E1F.png";
(*key point:scale up image to smooth the edges*)
img = ImageResize[img2, 4 ImageDimensions[img2]];
mask = ChanVeseBinarize[img, TargetColor -> {1., 1., 1.}, "LengthPenalty" -> 10];
mask1 = Blur[Erosion[ColorNegate[mask], 8], 10];
f[col_] := Rasterize[SetAlphaChannel[img, mask1], Background -> col, 
                     ImageSize -> ImageDimensions@img2]
GraphicsGrid[{{f@Red, f@Blue, f@Green}}]

görüntü açıklamasını buraya girin

Büyütmek için tıklayın

Düzenle 2

Görüntüdeki hale ve arka plan kusurlarının boyutu hakkında bir fikir edinmek için :

img = Import@"http://i.stack.imgur.com/k7E1F.png";
Join[{img}, MapThread[Binarize, {ColorSeparate[img, "HSB"], {.01, .01, .99}}]]

görüntü açıklamasını buraya girin

ColorNegate@ImageAdd[EntropyFilter[img, 1] // ImageAdjust, ColorNegate@img]

görüntü açıklamasını buraya girin


Ne yazık ki, benim makinemde kodunuz aynı kalitede sonuç üretmiyor. Sorudaki gibi 500x500 resmi img miydi? Evetse, belki bir mac / windows şey ...
Matthias Odisio

@Matthias Evet, img orijinalinden bir kopyası / yapıştırmasıdır. Windows'ta Mma 8.01.
Dr Belisarius

Oh ... belki de optimize edici, küçük aritmetik gürültü nedeniyle farklı bir sonuç üretir. Her neyse, bu parametre setini kullanarak sizin için iyi çalıştığına sevindim.
Matthias Odisio

İşe yarıyor gibi görünmüyor. Sadece kenarları bulanıklaştırıyor.
user541686

48

Bu işlev, ek küçük ama gözle görülür bir iyileştirme için Mark Ransom tarafından açıklanan ters karışımı uygular:

reverseBlend[img_Image, alpha_Image, bgcolor_] :=
 With[
  {c = ImageData[img], 
   a = ImageData[alpha] + 0.0001, (* this is to minimize ComplexInfinitys and considerably improve performance *)
   bc = bgcolor},

  ImageClip@
   Image[Quiet[(c - bc (1 - a))/a, {Power::infy, 
       Infinity::indet}] /. {ComplexInfinity -> 0, Indeterminate -> 0}]
  ]

Bu, arka plan kaldırma işlevidir. thresholdParametre görüntünün ilk çiftlemeye için kullanılan, minSizeCorrectionçiftlemeye sonra kaldırılır küçük önemsiz bileşenleri boyut sınırını verdiği içindir.

removeWhiteBackground[img_, threshold_: 0.05, minSizeCorrection_: 1] :=
  Module[
  {dim, bigmask, mask, edgemask, alpha},
  dim = ImageDimensions[img];
  bigmask = 
   DeleteSmallComponents[
    ColorNegate@
     MorphologicalBinarize[ColorNegate@ImageResize[img, 4 dim], threshold], 
    Round[minSizeCorrection Times @@ dim/5]];
  mask = ColorNegate@
    ImageResize[ColorConvert[bigmask, "GrayScale"], dim];
  edgemask = 
   ImageResize[
    ImageAdjust@DistanceTransform@Dilation[EdgeDetect[bigmask, 2], 6],
     dim];
  alpha = 
   ImageAdd[
    ImageSubtract[
     ImageMultiply[ColorNegate@ColorConvert[img, "GrayScale"], 
      edgemask], ImageMultiply[mask, edgemask]], mask];
  SetAlphaChannel[reverseBlend[img, alpha, 1], alpha]
  ]

Fonksiyonun test edilmesi:

img = Import["http://i.stack.imgur.com/k7E1F.png"];

background = 
  ImageCrop[
   Import["http://cdn.zmescience.com/wp-content/uploads/2011/06/\
forest2.jpg"], ImageDimensions[img]];

result = removeWhiteBackground[img]

ImageCompose[background, result]
Rasterize[result, Background -> Red]
Rasterize[result, Background -> Black]

Örneklem

Nasıl çalıştığına dair kısa açıklama:

  1. Nispeten hassas keskin kenarlar üreten favori ikili arıtma yönteminizi seçin

  2. Yukarı ölçeklenmiş bir görüntüye uygulayın, ardından elde edilenin maskboyutunu orijinal boyuta küçültün . Bu bize kenar yumuşatma verir. İşin çoğu bitti.

  3. Küçük bir iyileştirme için, görüntüyü negatifinin parlaklığını alfa olarak kullanarak arka planla karıştırın, ardından elde edilen görüntüyü orijinalin edgemasküzerinde, kenarlardaki beyaz piksellerin görünürlüğünü azaltmak için kenarların etrafındaki ince bir bölgede ( ) karıştırın. Bu işlemlere karşılık gelen alfa kanalı hesaplanır (bir şekilde şifreli ImageMultiply/Addifade).

  4. Şimdi alfa kanalının bir tahminine sahibiz, böylece tersine harmanlama yapabiliriz.

Adım 3 ve 4 o kadar gelişmez, ancak fark görünür.


@belisarius, İngilizce ile ilgili değil, adımın çoğu için alışılmadık göründüğünü biliyorum :-)
Szabolcs

Oldukça std gibi görünüyor. Macar soyadı benim için :)
Dr. belisarius

@belisarius Aslında bu bir ön addır veya daha doğrusu verilen bir addır, tıpkı Macarcada soyadı önce ve verilen ad soyadıdır.
Szabolcs

2
Kasanın gölgesi hala 2. figürde altta grimsi bir bant olarak duruyor ...
Sjoerd C. de Vries

@ SjoerdC.deVries Bu doğru, ama bence bu görev için böyle olmalı ... bunun bir gölge olduğunu ve nesnenin bir parçası olmadığını söylemenin bir yolu yok. Amazon'daki çoğu resmin ya gölgeleri vardı ya da sıkıcı derecede önemsizdi, bu yüzden bununla gittim.
Szabolcs

22

Genel olarak konuşacağım, özellikle Mathematica'ya referansla değil. Bu operasyonların zor mu yoksa önemsiz mi olduğu hakkında hiçbir fikrim yok.

İlk adım, görüntünün kenarındaki pikseller için bir alfa (şeffaflık) düzeyi tahmin etmektir. Şu anda katı bir eşik kullanıyorsunuz, yani alfa ya% 0 tamamen şeffaf ya da% 100 tamamen opak. Arka planın toplam beyazı ile görüntünün tartışılmaz bir parçası olan renkler arasında bir aralık tanımlamalı ve uygun bir oran ayarlamalısınız - eğer arka plana daha yakınsa düşük alfa ve daha koyu kesime daha yakınsa yüksek alfa. Bundan sonra, çevreleyen alfa değerlerine göre ayarlamalar yapabilirsiniz - bir piksel şeffaflıkla ne kadar çok çevrelenirse, şeffaf olma olasılığı o kadar artar.

Alfa değerlerine sahip olduğunuzda, uygun rengi elde etmek için ters bir karışım yapmanız gerekir. Bir görüntü, bir arka plan üzerinde görüntülendiğinde bu formül kullanılarak alfa değerine göre harmanlanır arka plan rengi ve ön renktir. Senin durumunda arka plan beyazdır (255255255) ve formülü tersine böylece ön plan rengi, bilinmemektedir: . Ne zaman formül sıfıra a böle çağrısı fakat renk meselesi zaten bu yüzden sadece siyah ya da beyaz kullanmaz yok.c = bc*(1-a)+fc*abcfcfc = (c - bc*(1-a))/aa=0


3
Mükemmel cevap. Alfa tahmini aslında bütün bir araştırma alanıdır, örneğin ai.stanford.edu/~ruzon/alpha
mpenkov

2
Kabul edildi, harika yanıt; teşekkürler Mark! Ödül için (stackoverflow bir tane eklememe izin verdiğinde), tam olarak uygulanan çözümden hangisi en iyi görünüyorsa onunla gitmeyi planlıyorum. Şimdiye kadar belisarius's, düşünüyorum.
Dreeves

11

Belisarius'un maske neslinden biraz yardım alarak Mark Ransom'un yaklaşımını uygulamaya bir deneme yapın:

Nesnenin sınırını bulun:

img1 = SetAlphaChannel[img, 1];
erosionamount=2;
mb = ColorNegate@ChanVeseBinarize[img, TargetColor -> {1., 1., 1}, 
      "LengthPenalty" -> 10];
edge = ImageSubtract[Dilation[mb, 2], Erosion[mb, erosionamount]];

ImageApply[{1, 0, 0} &, img, Masking ->edge]

şekil kenarı

Alfa değerlerini ayarlayın:

edgealpha = ImageMultiply[ImageFilter[(1 - Mean[Flatten[#]]^5) &, 
   ColorConvert[img, "GrayScale"], 2, Masking -> edge], edge];
imagealpha = ImageAdd[edgealpha, Erosion[mb, erosionamount]];
img2 = SetAlphaChannel[img, imagealpha];

Ters renk karışımı:

img3 = ImageApply[Module[{c, \[Alpha], bc, fc},
   bc = {1, 1, 1};
   c = {#[[1]], #[[2]], #[[3]]};
   \[Alpha] = #[[4]];
   If[\[Alpha] > 0, Flatten[{(c - bc (1 - \[Alpha]))/\[Alpha], \[Alpha]}], {0., 0., 
   0., 0}]] &, img2];

Show[img3, Background -> Pink]

pembe arka plan

Bazı kenarların nasıl beyaz tüylere sahip olduğuna dikkat edin? Bunu ilk resimdeki kırmızı çerçeveyle karşılaştırın. Daha iyi bir kenar detektörüne ihtiyacımız var. Erozyon miktarını artırmak tüylere yardımcı olur, ancak diğer taraflar çok şeffaf hale gelir, bu nedenle kenar maskesinin genişliğinde bir denge vardır. Yine de, bulanıklık işlemi olmadığı düşünüldüğünde, oldukça iyi.

Sağlamlığını test etmek ve ne kadar otomatik olduğunu görmek için algoritmayı çeşitli görüntülerde çalıştırmak öğretici olacaktır.


Hmmm, bana göre img2, img3'ten daha iyi görünüyor (masa yüzeyinin altına bakın). Belki ters renk karışımı gereksizdir?
JxB

10

Sadece yeni başlayanlar olarak oynamak - bu kadar çok aracın mevcut olması şaşırtıcı.

b = ColorNegate[
    GaussianFilter[MorphologicalBinarize[i, {0.96, 0.999}], 6]];
c = SetAlphaChannel[i, b];
Show[Graphics[Rectangle[], Background -> Orange, 
     PlotRangePadding -> None], c]


9

Görüntü işlemede tamamen yeniyim ama işte sürüm 8'in yeni morfolojik görüntü işleme işlevleriyle biraz oynadıktan sonra elde ettiğim şey:

mask = DeleteSmallComponents[
   ColorNegate@
    Image[MorphologicalComponents[ColorNegate@img, .062, 
      Method -> "Convex"], "Bit"], 10000];
Show[Graphics[Rectangle[], Background -> Red, 
  PlotRangePadding -> None], SetAlphaChannel[img, ColorNegate@mask]]

görüntü


3
Bence Dreeves, kenarlardaki o sivri uçlu çizgilerden kurtulmaya çalışıyor.
Dr Belisarius

1
Doğru, bu haleyi azaltmak için iyi bir iş ama pürüzlülük bir anlaşma kırıcı olabilir. @belisarius, sürümünüz oldukça harika görünüyor!
dreeves

@dreeves Bulanıklıktan sonra bir mesafe dönüşümü kullanarak kenarların iyileştirilebileceğini düşünüyorum (benim versiyonumda), ancak bu Bay Wiz tarafından zaten not edilmişti, bu yüzden deneyi ona bırakıyorum.
Dr Belisarius

Ne yapar Method -> "Convex"? Belgelenmemiş.
Szabolcs

Üzgünüm! Aslında ilgisiz fonksiyonlar olan Morfolojik Bileşenler ve MorfolojikBinarize'ı karıştırdığımı fark ettim!
Szabolcs

6

Bunun için Photoshop kullanmanızı ve PNG olarak kaydetmenizi öneririm.


5
İyi nokta, ama Photoshop'un bunu bu kadar iyi yapmak için kullandığı algoritma nedir? (Tabii ki bu otomatik hale getirmek isteyen bir Ve her resim için Photoshop değnek büyü ile etrafta tıklamayın.)
dreeves

3
Bu arada, bunun belirtilmesi yararlı bir şey olduğunu düşünüyorum (Photoshop'un aklıma gelmemiş olabileceği o kadar büyük bir Mathematica ineği olabilirdim!). Ve Photoshop'ta bile yazılabilir olduğu ortaya çıktı, bu yüzden bu, photoshop küçük bir mathematica programıyla kopyalanamayan gerçekten zekice bir şey yapıyorsa, bu anlamda mümkün olan en iyi cevap olabilir.
Dreeves

5
Adobe'nin yazılımları için 500 smakeroo almasının bir nedeni var ;-).
Timo

7
Belki bir PhotoShop betiği tarafından oluşturulan görüntünün bir sürümünü
yayınlayabilirsiniz

5

Atabileceğiniz olası adımlar:

  • maskeyi genişletmek
  • bulanıklaştır
  • maskeyi kullanarak şeffaflığı beyaza olan mesafeye göre ayarlayın
  • maskeyi kullanarak doygunluğu önceden daha beyaz olan renkler daha doygun olacak şekilde ayarlayın.

İyi düşünceler; teşekkür ederim! Bunun için genel amaçlı bir kod almayı çok isterim. O zaman geri dönmek isterseniz, muhtemelen birkaç gün içinde (stackoverflow bize izin verdiğinde) büyük bir ödül koyacağız. Ki dalışın herhangi kandırılması eğer Aslında burada, bunu yaparken taahhüt :).
dreeves

@dreeves Kulağa hoş geliyor; Şu an zamanım yok ama ona geri dönmeye çalışacağım.
Bay Sihirbaz

3

"Neredeyse beyaza yakın" olan herhangi bir pikseli, şeffaflık kanalında aynı RGB rengine sahip bir piksel ve bir Sigmoid gradyanı ile değiştirin. Katıdan şeffafa doğrusal geçiş uygulayabilirsiniz, ancak Sinusoid veya Sigmoid veya Tanh, aradığınız kenarın keskinliğine bağlı olarak daha doğal görünürler, ortamdan hızlıca katı veya şeffaflığa doğru hareket ederler, ancak adım adım / ikili olarak değil tarz, şimdi sahip olduğun şey.

Bu şekilde düşün:

Diyelim ki R, G, B'nin her biri 0.0-1.0, sonra beyazı R + G + B = 1.0 * 3 = 3.0 olarak tek bir sayı olarak temsil edelim.

Her bir rengin birazını çıkarmak onu biraz "kirli beyaz" yapar, ancak 3'ünden birazını almak, onu herhangi birinden biraz daha fazla almaktır. Herhangi bir kanalda% 10'luk bir azalmaya izin verdiğinizi varsayalım: 1.0 * .10 = .1, Şimdi bu kaybı üçüne de dağıtın ve 0,1'den küçükse alfa kanalı için 0 ile 1 arasında bağlayın, öyle ki ( kayıp = 0.9) => 0 ve (kayıp = 1.0) => 1:

threshold=.10;
maxLoss=1.0*threshold;
loss=3.0-(R+G+B);
alpha=If[loss>maxLoss,0,loss/maxLoss];
(* linear scaling is used above *)
(* or use 1/(1 + Exp[-10(loss - 0.5maxLoss)/maxLoss]) to set sigmoid alpha *)
(* Log decay: Log[maxLoss]/Log[loss]
      (for loss and maxLoss <1, when using RGB 0-255, divide by 255 to use this one *)

setNewPixel[R,G,B,alpha];

Referans için:

maxLoss = .1;
Plot[{ 1/(1 + Exp[-10(loss - 0.5maxLoss)/maxLoss]),
       Log[maxLoss]/Log[loss],
       loss/maxLoss
     }, {loss, 0, maxLoss}]

Bunda sahip olduğunuz tek tehlike (veya faydası?), Aslında fotoğrafın bir parçası OLAN beyazları umursamamasıdır. Tüm beyazları çıkarır. Böylece beyaz bir araba resminiz varsa, içinde şeffaf yamalar olacaktır. Ancak sizin örneğinize göre, bu istenen bir etki gibi görünüyor.


Bence ChanVeseBinarize'nin fikri bu konuda akıllı olmak ve daha geniş bir beyaz alanın parçası olmadıkça, yani arka planın bir parçası olmadıkça beyaz pikselleri şeffaf hale getirmemek.
Dreeves

"Daha geniş alan" ile ilgili sorun, bunun önemli olabileceğidir, ancak küçük alan önemsiz olabilir. Beyaz bir arabada, tüm taraf önemli olurdu, ancak büyük bir beyaz yama olarak etiketlenirdi. Beyaz bir arka plana karşı iki kişi arasındaki boşluk küçük ve karmaşık kenarlı olurdu, ancak gitmesi gerekiyor. Boltzman Makine tarzı bir yapay zekanın ortak şekilleri tanıması ve beyazın uzay mı yoksa nesnenin bir parçası mı olduğunu görmeniz gerekir, ancak henüz orada değiliz.
Gregory Klopper

1
Biraz farklı bakış açılarından 2 görüntü de çekebilir ve ardından kapanmaların meydana geldiği yere bağlı olarak hangi piksellerin arka plan olduğunu bulmak için stereo görüntülemeden boyutsallık çıkarımını kullanabilirsiniz.
Gregory Klopper
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.