Xóa nền trắng khỏi ảnh và làm cho nó trong suốt


82

Chúng tôi đang cố gắng thực hiện những điều sau trong Mathematica - RMagick xóa nền trắng khỏi hình ảnh và làm cho nó trong suốt .

Nhưng với những bức ảnh thực tế, nó trông tệ hại (giống như có một vầng hào quang xung quanh hình ảnh).

Đây là những gì chúng tôi đã thử cho đến nay:

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

Đây là một ví dụ về những gì điều đó làm.

Ảnh gốc:

ảnh gốc

Hình ảnh có nền trắng được thay thế bằng không có nền (hoặc, với mục đích trình diễn ở đây, nền màu hồng):

hình ảnh có nền trong suốt - ở đây thực ra là nền màu hồng, để làm rõ vấn đề vầng hào quang

Bất kỳ ý tưởng để loại bỏ quầng sáng đó? Chỉnh sửa những thứ như LevelPenalty, tôi chỉ có thể làm cho quầng sáng biến mất với cái giá là mất một số hình ảnh.

CHỈNH SỬA: Vì vậy, tôi có thể so sánh các giải pháp cho tiền thưởng, vui lòng cấu trúc giải pháp của bạn như trên, cụ thể là một hàm độc lập có tên là unground-một cái gì đó lấy một hình ảnh và trả về một hình ảnh có nền trong suốt.


1
Cảm ơn rất nhiều vì sự giúp đỡ cho đến nay, tất cả mọi người! Tiền thưởng lớn sẽ đến với điều này ngay khi stackoverflow cho phép tôi thêm một. Và, theo tinh thần của stackoverflow như được nêu rõ bởi những người sáng lập, bạn nên thoải mái trao đổi với nhau để đưa ra câu trả lời chính xác nhất!
dreeves

3
Tiền thưởng 500 đầu tiên và sau đó là "Tôi khuyến khích tất cả các bạn nên vay của nhau một cách tự do để cải thiện nó nếu có thể!" - bạn muốn một cuộc đấu chó, phải không?
Mr.Wizard

@ Mr.Wizard, :) Mặc dù vậy, tôi không bịa ra rằng những người sáng lập (Jeff và Joel) đã nói ngay từ đầu rằng điều đó được khuyến khích. Ý tưởng là câu trả lời hàng đầu phải là một câu trả lời thực sự đầy đủ và dứt khoát. (Và rõ ràng là tôi có động cơ thầm kín cũng trong trường hợp này!)
dreeves

2
Đối với quá tò mò, điều này "Fredrik" trạm làm việc máy tính của IKEA: ikea.com/us/en/catalog/products/60111123
Arnoud Buzing

1
@dreeves, tôi đã sử dụng tineye.com .
Arnoud Buzing vào

Câu trả lời:


45

Có lẽ, tùy thuộc vào chất lượng cạnh bạn cần:

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]

nhập mô tả hình ảnh ở đây

Biên tập

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

nhập mô tả hình ảnh ở đây

Bấm để phóng to

Chỉnh sửa 2

Chỉ để có được ý tưởng về mức độ không hoàn hảo của quầng sáng và hậu cảnh trong hình ảnh:

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

nhập mô tả hình ảnh ở đây

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

nhập mô tả hình ảnh ở đây


Đáng buồn thay, trên máy của tôi, mã của bạn không tạo ra kết quả cùng chất lượng. Img có phải là hình ảnh 500x500 như đã đăng trong câu hỏi không? Nếu có, có lẽ là một điều mac / cửa sổ ...
Matthias Odisio

@Matthias Có, img là bản sao / dán từ bản gốc. Mma 8.01 trên windows.
Tiến sĩ belisarius

Ồ ... có lẽ trình tối ưu hóa tạo ra một kết quả khác do nhiễu số học nhỏ. Dù sao, tôi rất vui vì nó hoạt động tốt cho bạn khi sử dụng bộ thông số này.
Matthias Odisio

Điều đó không giống như nó hoạt động. Nó chỉ làm mờ các cạnh.
user541686 11/11/11

48

Chức năng này thực hiện sự pha trộn ngược được mô tả bởi Mark Ransom, để có thêm một cải tiến nhỏ nhưng rõ ràng:

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

Đây là chức năng xóa nền. Các thresholdtham số được sử dụng cho binarization ban đầu của hình ảnh, minSizeCorrectionlà cho tinh chỉnh giới hạn kích thước của các thành phần rác nhỏ để được gỡ bỏ sau khi binarization.

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

Kiểm tra chức năng:

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]

Mẫu vật

Giải thích ngắn gọn về cách nó hoạt động:

  1. Chọn phương pháp phân tích binariaztion yêu thích của bạn để tạo ra các cạnh sắc tương đối chính xác

  2. Áp dụng nó cho một hình ảnh được tăng tỷ lệ, sau đó giảm tỷ lệ thu được maskvề kích thước ban đầu. Điều này cung cấp cho chúng tôi khử răng cưa. Phần lớn công việc đã xong.

  3. Đối với một cải tiến nhỏ, trộn hình ảnh vào nền bằng cách sử dụng độ sáng âm của nó là alpha, sau đó trộn hình ảnh thu được với bản gốc trong một vùng mỏng xung quanh các cạnh ( edgemask) để giảm khả năng hiển thị của các pixel màu trắng trên các cạnh. Kênh alpha tương ứng với các phép toán này được tính toán ( ImageMultiply/Addbiểu thức hơi khó hiểu ).

  4. Bây giờ chúng ta có một ước tính về kênh alpha để chúng ta có thể thực hiện trộn ngược lại.

Bước 3 & 4 không cải thiện nhiều nhưng có thể thấy sự khác biệt.


@belisarius nó không phải về tiếng Anh, tôi biết tên của tôi trông rất bất thường đối với hầu hết :-)
Szabolcs

Trông giống như một std đẹp. Họ Hungary cho tôi :)
Tiến sĩ Belisarius

@belisarius Thực ra đó là tên riêng, hay chính xác hơn là một tên riêng, như trong tiếng Hungary, họ đứng trước và tên sau.
Szabolcs

2
Cái bóng của vỏ máy vẫn ở đó trong hình thứ 2 như một dải màu xám ở dưới cùng ...
Sjoerd C. de Vries

@ SjoerdC.deVries Đúng là như vậy, nhưng tôi nghĩ đối với nhiệm vụ này thì nó phải như vậy ... không có cách nào để nói đó là bóng và không phải là một phần của đối tượng. Hầu hết hình ảnh trên Amazon hoặc có bóng hoặc quá tầm thường, vì vậy tôi đã chọn bức này.
Szabolcs

22

Tôi sẽ nói chung chung, không liên quan cụ thể đến Mathematica. Tôi không biết liệu những hoạt động này khó hay nhỏ.

Bước đầu tiên là ước tính mức alpha (độ trong suốt) cho các pixel ở rìa của hình ảnh. Hiện tại, bạn đang sử dụng ngưỡng nghiêm ngặt, vì vậy alpha là 0% hoàn toàn trong suốt hoặc 100% hoàn toàn không trong suốt. Bạn nên xác định phạm vi giữa tổng màu trắng của nền và các màu là một phần không thể chối cãi của hình ảnh và đặt tỷ lệ thích hợp - nếu nó có màu gần với nền hơn thì alpha thấp và nếu nó gần với ngưỡng tối hơn thì nó alpha cao. Sau đó, bạn có thể thực hiện các điều chỉnh dựa trên các giá trị alpha xung quanh - pixel càng được bao quanh bởi độ trong suốt, thì bản thân nó càng có khả năng trong suốt.

Khi bạn có các giá trị alpha, bạn cần thực hiện trộn ngược để có được màu thích hợp. Khi một hình ảnh được hiển thị trên nền, nó được pha trộn theo giá trị alpha bằng công thức c = bc*(1-a)+fc*atrong đó bclà màu nền và fclà màu nền trước. Trong trường hợp của bạn nền là màu trắng (255.255.255) và màu foreground là không rõ, vì vậy chúng tôi đảo ngược công thức: fc = (c - bc*(1-a))/a. Khi a=0công thức yêu cầu một số chia cho 0, nhưng màu sắc không quan trọng, vì vậy chỉ cần sử dụng màu đen hoặc trắng.


3
Câu trả lời chính xác. Ước tính alpha thực sự là một lĩnh vực nghiên cứu toàn bộ, ví dụ: ai.stanford.edu/~ruzon/alpha
mpenkov

2
Đồng ý, câu trả lời tuyệt vời; cảm ơn Mark! Đối với tiền thưởng (khi stackoverflow cho phép tôi thêm một) mặc dù tôi dự định chọn bất kỳ giải pháp nào được triển khai đầy đủ có vẻ tốt nhất. Tôi đang nghĩ cho đến nay của belisarius.
dreeves

11

Dưới đây là một thử nghiệm thực hiện phương pháp của Mark Ransom, với một số trợ giúp từ thế hệ mặt nạ của belisarius:

Xác định vị trí ranh giới của đối tượng:

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]

cạnh hình

Đặt các giá trị alpha:

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

Sự pha trộn màu ngược:

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]

nền màu hồng

Chú ý xem một số cạnh có lông tơ màu trắng? So sánh điều đó với đường viền màu đỏ trong hình ảnh đầu tiên. Chúng tôi cần một máy dò cạnh tốt hơn. Tăng lượng xói mòn giúp làm mờ lông tơ, nhưng sau đó các mặt khác trở nên quá trong suốt, do đó, có sự cân bằng về chiều rộng của mặt nạ cạnh. Tuy nhiên, nó khá tốt, xem xét không có hoạt động mờ.

Sẽ là hướng dẫn để chạy thuật toán trên nhiều hình ảnh khác nhau để kiểm tra độ mạnh mẽ của nó, để xem nó tự động như thế nào.


Hmmm, đối với tôi img2 trông đẹp hơn (xem dưới cùng của mặt bàn) so với img3. Có lẽ sự pha trộn màu ngược lại là không cần thiết?
JxB

10

Chỉ chơi xung quanh khi mới bắt đầu - thật ngạc nhiên khi có rất nhiều công cụ.

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


9

Tôi hoàn toàn mới về xử lý hình ảnh nhưng đây là những gì tôi nhận được sau khi chơi với các chức năng xử lý hình ảnh hình thái học mới của phiên bản 8:

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

hình ảnh


3
Tôi nghĩ rằng dreeves đang cố gắng loại bỏ những đường răng cưa ở các cạnh.
Tiến sĩ belisarius

1
Đúng vậy, điều này thực hiện một công việc tốt trong việc giảm quầng sáng đó nhưng sự lởm chởm có thể là một yếu tố phá vỡ thỏa thuận. @belisarius, phiên bản của bạn trông khá tuyệt!
dreeves

@dreeves Tôi nghĩ rằng các cạnh có thể được cải thiện (trong phiên bản của tôi) bằng cách sử dụng biến đổi khoảng cách sau khi làm mờ, nhưng điều đó đã được ông Wiz lưu ý, vì vậy tôi để thử nghiệm cho ông ấy.
Tiến sĩ belisarius

Làm gì Method -> "Convex"? Nó không được ghi lại.
Szabolcs

Tôi xin lỗi! Tôi nhận ra rằng tôi đã nhầm lẫn giữa MorphologicalComponents và MorphologicalBinarize mà trên thực tế là các chức năng không liên quan!
Szabolcs

6

Tôi khuyên bạn nên sử dụng Photoshop cho việc này và lưu dưới dạng PNG.


5
Tốt, nhưng thuật toán mà photoshop sử dụng để làm tốt điều này là gì? (Và tất nhiên chúng tôi muốn tự động hoá này, không bấm xung quanh với Magic Wand trong photoshop cho mỗi hình ảnh.)
dreeves

3
Nhân tiện, tôi nghĩ rằng đây là một điều hữu ích để chỉ ra (tôi có thể dễ dàng có được một con mọt sách Toán học lớn đến mức photoshop có thể không xảy ra với tôi!). Và hóa ra nó thậm chí còn có thể viết được bằng photoshop nên đây thậm chí có thể là câu trả lời tốt nhất có thể theo nghĩa đó, nếu photoshop đang làm một điều gì đó thực sự thông minh mà không thể bị trùng lặp với một chương trình toán học nhỏ.
làn sóng

5
Có một lý do tại sao Adobe có thể tính phí 500 smakeroos cho phần mềm của họ ;-).
Timo

7
Có lẽ bạn có thể gửi một phiên bản của hình ảnh được tạo ra bởi một kịch bản PhotoShop (không tay can thiệp :-) để tham khảo - chúng tôi sẽ biết những gì chúng ta phải nhịp ...
cormullion

5

Các bước khả thi bạn có thể thực hiện:

  • mở rộng mặt nạ
  • làm mờ nó
  • sử dụng mặt nạ, đặt độ trong suốt theo khoảng cách từ màu trắng
  • bằng cách sử dụng mặt nạ, điều chỉnh độ bão hòa sao cho các màu trắng trước đây được bão hòa hơn.

Ý nghĩ tốt; cảm ơn bạn! Rất thích nhận được một số mã mục đích chung cho việc này. Chúng tôi có thể sẽ đặt một khoản tiền thưởng lớn trong một vài ngày (khi stackoverflow cho phép chúng tôi) nếu bạn muốn quay lại lúc đó. Trong thực tế, tôi xin cam kết làm như vậy, nếu đó là bất kỳ sự cám dỗ để bổ nhào vào :).
dreeves

@dreeves Nghe có vẻ tốt với tôi; Tôi không có thời gian bây giờ, nhưng tôi sẽ cố gắng quay lại với nó.
Mr.Wizard

3

Chỉ cần thay thế bất kỳ pixel nào "gần như gần với màu trắng" bằng một pixel có cùng màu RGB và gradient Sigmoid trên kênh trong suốt. Bạn có thể áp dụng chuyển tiếp tuyến tính từ rắn sang trong suốt, nhưng Hình sin hoặc Hình chữ nhật hoặc Tanh trông tự nhiên hơn, tùy thuộc vào độ sắc nét của cạnh bạn đang tìm kiếm, chúng nhanh chóng di chuyển từ môi trường trung bình sang rắn hoặc trong suốt, nhưng không theo chiều kim / nhị phân cách, đó là những gì bạn có bây giờ.

Nghĩ theo cách này:

Giả sử R, G, B là mỗi 0,0-1,0, sau đó hãy biểu diễn màu trắng dưới dạng một số duy nhất là R + G + B = 1,0 * 3 = 3,0.

Lấy một ít của mỗi màu ra ngoài sẽ làm cho nó hơi "trắng nhạt", nhưng lấy một ít của cả 3 màu sẽ khiến nó mất đi nhiều hơn một chút so với bất kỳ màu nào. Giả sử rằng bạn cho phép giảm 10% trên bất kỳ kênh nào: 1.0 * .10 = .1, Bây giờ hãy chia khoản lỗ này cho cả ba và ràng buộc nó giữa 0 và 1 đối với kênh alpha, nếu nó nhỏ hơn 0,1, như vậy ( lỗ = 0,9) => 0 và (lỗ = 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];

Để tham khảo:

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

Điều nguy hiểm (hoặc lợi ích?) Duy nhất mà bạn gặp phải, đó là điều này không quan tâm đến người da trắng thực sự LÀ một phần của bức ảnh. Nó loại bỏ tất cả lòng trắng. Vì vậy, nếu bạn có một bức ảnh về chiếc xe hơi màu trắng, nó sẽ có các mảng trong suốt bên trong. Nhưng từ ví dụ của bạn, đó có vẻ là một hiệu ứng mong muốn.


Tôi nghĩ ý tưởng của ChanVeseBinarize là phải thông minh về điều đó và không biến các pixel màu trắng trở nên trong suốt trừ khi chúng là một phần của vùng trắng lớn hơn, tức là, rất có thể là một phần của nền.
dreeves

Vấn đề với "diện tích lớn hơn" là điều đó có thể quan trọng, trong khi diện tích nhỏ có thể không quan trọng. Trên một chiếc xe màu trắng, toàn bộ phần bên sẽ rất quan trọng, nhưng sẽ được gắn thẻ là một mảng trắng lớn. Khoảng trống giữa hai người trên nền trắng sẽ nhỏ và có các cạnh phức tạp, nhưng nó cần phải đi. Bạn sẽ phải có một AI kiểu Máy Boltzman nhận dạng các hình dạng thông thường và xem liệu màu trắng là không gian hay một phần của vật thể, nhưng chúng ta vẫn chưa ở đó.
Gregory Klopper

1
Bạn cũng có thể chụp 2 hình ảnh từ các góc độ hơi khác nhau, sau đó sử dụng suy luận kích thước từ hình ảnh âm thanh nổi để tìm ra pixel nào là nền dựa trên vị trí xảy ra hiện tượng chèn.
Gregory Klopper
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.