이미지에서 흰색 배경을 제거하고 투명하게 만들기


82

Mathematica- RMagick에서 이미지에서 흰색 배경을 제거하고 투명하게 만드는 작업을 수행하려고합니다 .

그러나 실제 사진에서는 (이미지 주위에 후광이있는 것처럼) 형편 없게 보입니다.

지금까지 시도한 내용은 다음과 같습니다.

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

다음은 그 기능의 예입니다.

원본 이미지 :

원본 이미지

흰색 배경이 배경없이 대체 된 이미지 (또는 여기에서 데모 목적으로 분홍색 배경) :

투명한 배경이있는 이미지-실제로 여기에는 분홍색 배경이 있습니다.

그 후광을 없애기위한 아이디어가 있습니까? LevelPenalty와 같은 것을 조정하면 이미지의 일부를 잃는 대신 후광이 사라지도록 할 수 있습니다.

편집 : 그래서 현상금에 대한 솔루션을 비교할 수 있습니다. 위와 같이 솔루션을 구성하십시오. 즉 이미지를 가져 와서 투명한 배경으로 이미지를 반환하는 unground-something이라는 자체 포함 함수입니다.


1
지금까지 도움을 주셔서 감사합니다. 여러분! stackoverflow가 하나를 추가하자마자 큰 현상금이 올 것입니다. 그리고 창립자들이 말한 stackoverflow의 정신에 따라, 당신은 당신의 대답을 결정적인 것으로 만들기 위해 자유롭게 서로 훔쳐 야합니다!
dreeves

3
처음 500 개의 현상금을받은 다음 "가능한 한 개선하기 위해 서로에게 자유롭게 빌려주 길 바랍니다!" -개싸움을 원 하시죠?
Mr.Wizard 2011

@ Mr.Wizard, :) 창립자 (Jeff와 Joel)가 처음부터 장려한다고 말했지만 나는 그것을 구성하지 않습니다. 아이디어는 최고의 답변이 정말 완전하고 결정적인 답변이되는 것입니다. (그리고 분명히 나는이 경우에도
은밀한

2
지나치게 궁금한 분들을
Arnoud Buzing

1
@dreeves, 나는 tineye.com을 사용 했습니다 .
Arnoud Buzing 2011

답변:


45

필요한 가장자리 품질에 따라 다음과 같이 할 수 있습니다.

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]

여기에 이미지 설명 입력

편집하다

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}}]

여기에 이미지 설명 입력

클릭하면 확대됩니다

편집 2

이미지 의 후광 과 배경 결함 의 정도에 대한 아이디어를 얻으려면 :

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

여기에 이미지 설명 입력

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

여기에 이미지 설명 입력


슬프게도 내 컴퓨터에서 코드는 동일한 품질의 결과를 생성하지 않습니다. img는 질문에 게시 된 500x500 이미지였습니까? 그렇다면 아마도 맥 / 윈도우 일 것입니다 ...
Matthias Odisio 2011

@Matthias 예, img는 원본의 복사 / 붙여 넣기입니다. Windows의 MMA 8.01.
박사 벨리 사리우스

오 ... 아마도 옵티마이 저는 작은 산술 노이즈로 인해 다른 결과를 생성합니다. 어쨌든,이 매개 변수 세트를 사용하여 잘 작동하게되어 기쁩니다.
Matthias Odisio 2011

작동하지 않는 것 같습니다. 가장자리가 흐릿합니다.
user541686

48

이 기능은 작지만 눈에 띄는 개선을 위해 Mark Ransom이 설명한 역방향 혼합을 구현합니다.

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}]
  ]

이것은 배경 제거 기능입니다. threshold매개 변수 이미지의 이진화 초기에 사용되면,이 minSizeCorrection이진화 후 제거되는 작은 쓰레기 성분의 크기 한도를 미세하게 조정할 것이다.

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]
  ]

기능 테스트 :

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]

견본

작동 방식에 대한 간략한 설명 :

  1. 비교적 정확한 날카로운 모서리를 생성하는 선호하는 이진화 방법을 선택하십시오.

  2. 확대 된 이미지에 적용한 다음 얻은 이미지 mask를 원래 크기 로 축소합니다 . 이것은 우리에게 앤티 앨리어싱을 제공합니다. 대부분의 작업이 완료되었습니다.

  3. 약간 개선하려면 네거티브의 밝기를 알파로 사용하여 이미지를 배경에 혼합 한 다음 얻은 이미지를 가장자리 주변의 얇은 영역 ( edgemask) 에서 원본 위에 혼합하여 가장자리 의 흰색 픽셀의 가시성을 줄입니다. 이러한 연산에 해당하는 알파 채널이 계산됩니다 (다소 비밀스러운 ImageMultiply/Add표현).

  4. 이제 우리는 리버스 블렌드를 할 수 있도록 알파 채널의 추정치를 얻었습니다.

3 단계와 4 단계는 그다지 개선되지 않지만 차이는 눈에 보입니다.


@belisarius 그것은 영어에 관한 것이 아닙니다, 나는 내 이름이 대부분의 경우 매우 특이하게 보인다는 것을 압니다 :-)
Szabolcs

예쁜 std처럼 보입니다. 나를위한 헝가리 성 :)
belisarius 박사

@belisarius 실제로 그것은 이름 또는 더 정확하게 주어진 이름입니다. 헝가리어에서 성이 먼저 나오고 주어진 이름이 마지막입니다.
Szabolcs 2011

2
케이스의 그림자는 2 번째 그림에서 아래쪽에 회색 띠로 여전히 남아 있습니다 ...
Sjoerd C. de Vries

@ SjoerdC.deVries 사실입니다.하지만이 작업에 대해서는 그렇게되어야한다고 생각합니다. 그림자가 아니라 개체의 일부라고 말할 방법이 없습니다. 아마존에있는 대부분의 사진은 그림자가 있거나 지루할 정도로 사소한 것이므로이 사진을 사용했습니다.
Szabolcs 2011

22

저는 Mathematica와 관련하여 구체적으로 언급하지 않고 일반적으로 말하겠습니다. 나는 이러한 작업이 어렵거나 사소한 것인지 전혀 모릅니다.

첫 번째 단계는 이미지 가장자리의 픽셀에 대한 알파 (투명도) 수준을 추정하는 것입니다. 지금은 엄격한 임계 값을 사용하고 있으므로 알파는 완전 투명 0 % 또는 완전 불투명 100 %입니다. 배경의 전체 흰색과 이미지의 일부인 색상 사이의 범위를 정의하고 적절한 비율을 설정해야합니다. 색상이 배경에 더 가까우면 알파가 낮고 더 어두운 컷오프에 더 가까우면 적절한 비율을 설정해야합니다. 높은 알파. 그 후에 주변 알파 값을 기준으로 조정할 수 있습니다. 픽셀이 투명도로 둘러싸 일수록 자체적으로 투명해질 가능성이 높습니다.

알파 값이 있으면 적절한 색상을 얻기 위해 역 블렌드를 수행해야합니다. 이미지가 배경 위에 표시 될 때 수식하여 알파 값에 따라 배합 배경색이고 전경 색상이다. 귀하의 경우 배경은 흰색 (255,255,255)이고 전경색은 알 수 없으므로 공식을 반대로 바꿉니다 . 때 수식 0으로 나누기를 요구하지만, 색상이 문제 어쨌든 그래서 그냥 검은 색 또는 흰색으로 사용하지 않습니다.c = bc*(1-a)+fc*abcfcfc = (c - bc*(1-a))/aa=0


3
좋은 대답입니다. 알파 추정은 실제로 전체 연구 분야입니다. 예 : ai.stanford.edu/~ruzon/alpha
mpenkov 2011

2
동의하고 훌륭한 답변입니다. 감사합니다 마크! 현상금을 위해 (stackoverflow가 하나를 추가 할 수있을 때) 완전히 구현 된 솔루션이 가장 잘 보이는 것을 사용할 계획입니다. 지금까지 벨리 사리우스의 생각입니다.
dreeves

11

다음은 belisarius의 마스크 생성의 도움을 받아 Mark Ransom의 접근 방식을 구현하는 시도입니다.

개체의 경계를 찾습니다.

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]

그림 가장자리

알파 값을 설정합니다.

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

반전 색상 혼합 :

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]

분홍색 배경

일부 가장자리에 흰색 보풀이있는 것을 알 수 있습니까? 첫 번째 이미지의 빨간색 윤곽선과 비교하십시오. 더 나은 에지 감지기가 필요합니다. 침 식량을 늘리면 보풀에 도움이되지만 다른면이 너무 투명 해 지므로 가장자리 마스크의 너비에 절충안이 있습니다. 하지만 블러 작업 자체가 없다는 점을 고려하면 꽤 좋습니다.

다양한 이미지에서 알고리즘을 실행하여 견고성을 테스트하고 얼마나 자동인지 확인하는 것은 유익 할 것입니다.


흠, 나에게 img2는 img3보다 더 좋아 보입니다 (테이블 표면의 바닥 참조). 리버스 컬러 블렌드가 필요하지 않을까요?
JxB 2011

10

초보자로서 놀기만하면됩니다. 얼마나 많은 도구를 사용할 수 있는지 놀랍습니다.

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


9

저는 이미지 처리에 완전히 익숙하지 않지만 여기에 버전 8의 새로운 형태 학적 이미지 처리 기능을 사용하여 얻은 결과가 있습니다.

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

영상


3
나는 dreeves가 가장자리의 들쭉날쭉 한 선을 없애려고 노력하고 있다고 생각합니다.
박사 벨리 사리우스

1
사실, 이것은 그 후광을 줄이는 좋은 일을하지만, 들쭉날쭉 함은 거래를 방해 할 수 있습니다. @belisarius, 당신의 버전은 꽤 놀랍습니다!
dreeves

@dreeves 블러 후 거리 변환을 사용하여 가장자리를 개선 할 수 있다고 생각합니다 (내 버전에서는).하지만 Wiz 씨가 이미 언급 했으므로 실험을 그에게 맡깁니다.
박사 벨리 사리우스

무엇을 Method -> "Convex"합니까? 문서화되지 않았습니다.
Szabolcs

죄송 해요! 실제로 관련이없는 함수 인 MorphologicalComponents와 MorphologicalBinarize를 혼동했습니다.
Szabolcs

6

이를 위해 Photoshop을 사용하고 PNG로 저장하는 것이 좋습니다.


5
좋은 지적이지만 포토샵이이를 잘 수행하기 위해 사용하는 알고리즘은 무엇입니까? (물론 우리는 이것을 자동화하고 싶습니다. 각 이미지에 대해 포토샵에서 마술 지팡이로 클릭하지 마십시오.)
dreeves

3
그건 그렇고, 나는 이것이 지적하는 데 도움이되는 것이라고 생각합니다 (나는 포토샵이 나에게 발생하지 않았을 수도있는 Mathematica 괴상한 사람이 될 수 있습니다!). 그리고 그것은 심지어 포토샵에서 스크립팅이 가능하다는 것이 밝혀 졌기 때문에 이것은 포토샵이 작은 수학 프로그램으로는 복제 할 수없는 정말 영리한 일을하고 있다면 이것이 가능한 최선의 대답 일 수도 있습니다.
dreeves

5
Adobe가 소프트웨어에 대해 500 개의 smakeroos를 청구 할 수있는 이유가 있습니다 ;-).
Timo 2011

7
아마도 당신은 참조를 위해 PhotoShop 스크립트 (수동 개입 없음 :-)에 의해 생성 된 이미지의 버전을 게시 할 수 있습니다-우리는 우리가 이겨야 할 것을 알 것입니다 ...
cormullion

5

취할 수있는 조치 :

  • 마스크를 넓히다
  • 흐리게
  • 마스크를 사용하여 흰색과의 거리로 투명도를 설정하십시오.
  • 마스크를 사용하여 이전에 더 흰색이었던 색상이 더 포화되도록 채도를 조정합니다.

좋은 생각; 감사합니다! 이것에 대한 범용 코드를 얻고 싶습니다. 그때 돌아 오길 원하신다면 아마 며칠 안에 (스택 오버플로가 우리를 허락 할 때) 큰 현상금을 걸 것입니다. 사실, 나는 잠수하려는 유혹이 있다면 그렇게 할 것을 약속합니다. :)
dreeves

@dreeves 나에게 좋은 소리입니다. 지금은 시간이 없지만 다시 돌아가 보겠습니다.
Mr.Wizard 2011

3

"흰색에 거의 가까운"픽셀을 투명도 채널에서 동일한 RGB 색상 및 Sigmoid 그래디언트의 픽셀로 바꾸면됩니다. 솔리드에서 투명으로 선형 전환을 적용 할 수 있지만, 찾고있는 가장자리의 선명도에 따라 Sinusoid 또는 Sigmoid 또는 Tanh가 더 자연스럽게 보이며 중간에서 솔리드 또는 투명으로 빠르게 이동하지만 단계적 / 이진에서는 그렇지 않습니다. 그게 지금 당신이 가진 방식입니다.

다음과 같이 생각하십시오.

R, G, B가 각각 0.0-1.0이라고 가정하고 흰색을 R + G + B = 1.0 * 3 = 3.0과 같은 단일 숫자로 표현합시다.

각 색상을 조금씩 빼 내면 약간 "미색"이되지만 3 가지 모두 조금씩 빼는 것은 어느 하나를 조금 빼내는 것보다 훨씬 더 많이 빼앗 깁니다. 한 채널에서 10 % 감소를 허용한다고 가정 해 보겠습니다. 1.0 * .10 = .1, 이제이 손실을 세 개 모두에 분산하고 알파 채널에 대해 0과 1 사이에 바인딩합니다. 만약 그것이 .1보다 작다면 ( 손실 = 0.9) => 0 및 (손실 = 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];

참고로 :

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

당신이 가진 유일한 위험 (또는 이익?)은 실제로 사진의 일부인 백인에 대해서는 신경 쓰지 않는다는 것입니다. 모든 백인을 제거합니다. 따라서 흰색 자동차 사진이 있으면 투명 패치가 표시됩니다. 그러나 귀하의 예에서 그것은 원하는 효과 인 것 같습니다.


ChanVeseBinarize의 아이디어는 그것에 대해 현명하고 흰색 픽셀이 더 큰 흰색 영역의 일부가 아닌 경우, 즉 배경의 일부일 가능성이 매우 높은 경우가 아니면 흰색 픽셀을 투명하게 바꾸지 않는 것입니다.
dreeves

"큰 면적"의 문제는 그것이 중요 할 수있는 반면 작은 면적은 중요하지 않을 수 있다는 것입니다. 흰색 자동차에서는 전체 측면이 중요하지만 큰 흰색 패치로 태그가 지정됩니다. 흰색 배경에 대해 두 사람 사이의 공간은 작고 가장자리가 복잡하지만 가야합니다. Boltzman Machine 스타일의 AI가 일반적인 모양을 인식하고 흰색이 공간 또는 물체의 일부인지 확인해야하지만 아직 거기에 있지 않습니다.
Gregory Klopper 2011

1
약간 다른 관점에서 2 개의 이미지를 촬영 한 다음 스테레오 이미징에서 차원 추론을 사용하여 폐색이 발생하는 위치에 따라 배경이되는 픽셀을 찾을 수도 있습니다.
Gregory Klopper 2011
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.