Мы пытаемся сделать следующее в Mathematica - RMagick удаляет белый фон с изображения и делает его прозрачным .
Но на реальных фотографиях это выглядит ужасно (как будто вокруг изображения появляется ореол).
Вот что мы уже пробовали:
unground0[img_] := With[{mask = ChanVeseBinarize[img, TargetColor->{1.,1.,1.}]},
Rasterize[SetAlphaChannel[img, ImageApply[1-#&, mask]], Background->None]]]
Вот пример того, что это делает.
Исходное изображение:
Изображение с белым фоном, замененным без фона (или, в демонстрационных целях, с розовым фоном):
Есть идеи, как избавиться от этого ореола? Настраивая такие вещи, как LevelPenalty, я могу убрать ореол только за счет потери некоторой части изображения.
РЕДАКТИРОВАТЬ: Итак, я могу сравнить решения для награды, пожалуйста, структурируйте свое решение, как указано выше, а именно автономную функцию с именем unground-something, которая принимает изображение и возвращает изображение с прозрачным фоном.
Ответы:
Возможно, в зависимости от качества кромки вам потребуется:
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]
источник
Эта функция реализует обратное смешивание, описанное Марком Рэнсомом, для дополнительного небольшого, но видимого улучшения:
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]
Краткое объяснение того, как это работает:
Выберите свой любимый метод бинаризации, обеспечивающий относительно точные острые края
Примените его к увеличенному изображению, затем уменьшите полученное
mask
до исходного размера. Это дает нам антиалиасинг. Большая часть работы сделана.Для небольшого улучшения наложите изображение на фон, используя яркость его негатива в качестве альфа, а затем наложите полученное изображение на оригинал в тонкой области по краям (
edgemask
), чтобы уменьшить видимость белых пикселей по краям. Вычисляется альфа-канал, соответствующий этим операциям (несколько загадочноеImageMultiply/Add
выражение).Теперь у нас есть оценка альфа-канала, поэтому мы можем выполнить обратное смешивание.
Шаги 3 и 4 не сильно улучшаются, но разница заметна.
источник
Я буду говорить в общем, а не конкретно в отношении Mathematica. Не знаю, сложны ли эти операции или тривиальны.
Первый шаг - оценить уровень альфа (прозрачности) для пикселей по краю изображения. Прямо сейчас вы используете строгий порог, поэтому альфа либо 0% полностью прозрачна, либо 100% полностью непрозрачна. Вы должны определить диапазон между общим белым цветом фона и цветами, которые, несомненно, являются частью изображения, и установить соответствующую пропорцию - если он ближе по цвету к фону, это низкий альфа, а если он ближе к более темному отсечению, то он высокая альфа. После этого вы можете вносить корректировки на основе окружающих альфа-значений - чем больше пиксель окружен прозрачностью, тем больше вероятность, что он сам будет прозрачным.
Когда у вас есть альфа-значения, вам нужно выполнить обратное смешивание, чтобы получить правильный цвет. Когда изображение отображается поверх фона, оно смешивается в соответствии со значением альфа-канала с использованием формулы,
c = bc*(1-a)+fc*a
гдеbc
- цвет фона, аfc
- цвет переднего плана. В вашем случае фон белый (255255255) и цвет переднего плана неизвестность, поэтому мы перевернем формулуfc = (c - bc*(1-a))/a
. Когдаa=0
формула требует деления на ноль, но цвет все равно не имеет значения, просто используйте черный или белый.источник
Вот попытка реализовать подход Марка Рэнсома с некоторой помощью генерации масок Велизария:
Найдите границу объекта:
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]
Заметили, что на некоторых краях есть белый пушок? Сравните это с красным контуром на первом изображении. Нам нужен детектор края получше. Увеличение степени эрозии помогает с пухом, но тогда другие стороны становятся слишком прозрачными, так что приходится выбирать ширину маски края. Тем не менее, это довольно неплохо, учитывая, что операции размытия как таковой нет.
Было бы поучительно запустить алгоритм на множестве изображений, чтобы проверить его надежность, чтобы увидеть, насколько он автоматический.
источник
Просто поиграйте новичком - просто поразительно, сколько инструментов доступно.
b = ColorNegate[ GaussianFilter[MorphologicalBinarize[i, {0.96, 0.999}], 6]]; c = SetAlphaChannel[i, b]; Show[Graphics[Rectangle[], Background -> Orange, PlotRangePadding -> None], c]
источник
Я совершенно новичок в обработке изображений, но вот что я получил после некоторой игры с новыми функциями обработки морфологических изображений версии 8:
mask = DeleteSmallComponents[ ColorNegate@ Image[MorphologicalComponents[ColorNegate@img, .062, Method -> "Convex"], "Bit"], 10000]; Show[Graphics[Rectangle[], Background -> Red, PlotRangePadding -> None], SetAlphaChannel[img, ColorNegate@mask]]
источник
Method -> "Convex"
делать? Это не задокументировано.Я рекомендую использовать для этого Photoshop и сохранить как PNG.
источник
Возможные шаги, которые вы могли бы предпринять:
источник
Просто замените любой пиксель, который «почти белый», пикселем того же цвета RGB и сигмовидным градиентом на канале прозрачности. Вы можете применить линейный переход от твердого к прозрачному, но синусоида, сигмоида или тан выглядят более естественно, в зависимости от резкости края, который вы ищете, они быстро переходят от среднего к твердому или прозрачному, но не в пошаговом / двоичном манера, которая есть у вас сейчас.
Подумайте об этом так:
Скажем, R, G, B равны 0,0–1,0, а затем представим белый цвет одним числом как R + G + B = 1,0 * 3 = 3,0.
Если убрать немного каждого цвета, он станет немного «не совсем белым», но если убрать все три цвета, то получится гораздо больше, чем немного от любого другого. Допустим, вы допускаете снижение на 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}]
Единственная опасность (или преимущество?) В этом заключается в том, что он не заботится о белых тонах, которые на самом деле ЯВЛЯЮТСЯ частью фотографии. Удаляет все белые пятна. Так что если у вас есть фотография белой машины, на ней будут прозрачные пятна. Но, судя по вашему примеру, это желаемый эффект.
источник