Почему фильтр Pixel Bender в Toolkit ведет себя иначе, чем в приложении Flex/Air?
Итак, я попробовал этот более простой фильтр с тем же кодом Air, как показано ниже:
<languageVersion : 1.0;>
kernel NewFilter
< namespace : "Your Namespace";
vendor : "Your Vendor";
version : 1;
description : "your description";
>
{
input image4 src;
output pixel4 dst;
void
evaluatePixel()
{
pixel4 cPix = sampleNearest(src,outCoord());
pixel3 RGB = cPix .rgb;
float r = RGB.r;
float g = RGB.g;
float b = RGB.b;
//float minVal = min(r, g);
dst = pixel4(r, g, b, 1);
}
}
Оказывается, если я раскомментирую эту строку float minVal = min(r, g);
Я больше не получаю оригинальную картинку, но вот: Результат
Вместо этого: Оригинал
Если бы кто-то мог объяснить это мне... Я был бы очень благодарен...
//------------------------------------------------------------------
//------------------- ORIGINAL POST --------------------------------
Я пытаюсь сделать фильтр пиксельного бендера для приложения flex, который изменяет выбранный диапазон значений оттенка входного изображения на определенное новое значение оттенка. Я сделал такой фильтр в Pixel Bender Toolkit, и он дает удовлетворительные результаты.
Это код для этого фильтра:
<languageVersion : 1.0;>
kernel ColorChange
< namespace : "Your Namespace";
vendor : "Your Vendor";
version : 1;
description : "your description";
>
{
input image4 src;
output pixel4 dst;
parameter float HUE
<
minValue: 0.;
maxValue: 359.9;
defaultValue: 0.;
>;
parameter float SAT
<
minValue: -1.;
maxValue: 1.;
defaultValue: 0.;
>;
parameter float VAL
<
minValue: -1.;
maxValue: 1.;
defaultValue: 0.;
>;
parameter float MIN_RANGE
<
minValue: 0.;
maxValue: 360.;
defaultValue: 0.;
>;
parameter float MAX_RANGE
<
minValue: 0.;
maxValue: 360.;
defaultValue: 360.;
>;
void
evaluatePixel()
{
pixel4 cPix = sample(src,outCoord());
pixel3 RGB = cPix.rgb;
float3 HSV;
//--------------------------------------------------------------
// CONVERT RGB TO HSV
//--------------------------------------------------------------
pixel1 r = RGB.r;
pixel1 g = RGB.g;
pixel1 b = RGB.b;
pixel1 minVal = min(min(r, g), b);
pixel1 maxVal = max(max(r, g), b);
pixel1 delta = maxVal - minVal;
HSV[2] = maxVal;
if (maxVal == 0.) {
HSV[0] = 0.;
HSV[1] = 0.;
}
else
{
HSV[1] = delta / maxVal;
}
if(r == maxVal)
HSV[0] = (g-b)/delta;
else if(g == maxVal)
HSV[0] = 2. + (b-r) / delta;
else
HSV[0] = 4. + (r-g) / delta;
HSV[0] *= 60.;
if(HSV[0] <0.)
HSV[0] += 360.;
//--------------------------------------------------------------
// FILTER RANGE OF HUE
//--------------------------------------------------------------
if((HSV[0] < MIN_RANGE) || (HSV[0] > MAX_RANGE))
{
dst = cPix;
}
else
{
//--------------------------------------------------------------
// CHNAGE HSV
//--------------------------------------------------------------
float hH = HUE;
float sS = SAT;
float vV = VAL;
HSV[0] = HUE;
HSV[1] += SAT;
if(HSV[1] > 1.)
HSV[1] = 1.;
else if(HSV[1] < 0.)
HSV[1] = 0.;
HSV[2] += VAL;
if(HSV[2] > 1.)
HSV[2] = 1.;
else if(HSV[2] < 0.)
HSV[2] = 0.;
//----------------------------------------------------------------------
// CONVERT HSV TO RGB
//----------------------------------------------------------------------
float h = HSV[0];// / 360.;
float s = HSV[1];// / 100. * 255.;
float v = HSV[2];// / 100. * 255.;
if (s == 0.) {
RGB.r = v;
RGB.g = v;
RGB.b = v;
} else {
h = h / 60.;
int var_i = int(floor(h));
float f = h - float(var_i);
float p = v * (1.-s);
float q = v * (1.-s*f);
float t = v * (1.-s*(1.-f));
if (var_i == 0) {
RGB.r = v;
RGB.g = t;
RGB.b = p;
}
else if (var_i == 1) {
RGB.r = q;
RGB.g = v;
RGB.b = p;
}
else if (var_i == 2) {
RGB.r = p;
RGB.g = v;
RGB.b = t;
}
else if (var_i == 3) {
RGB.r = p;
RGB.g = q;
RGB.b = v;
}
else if (var_i == 4) {
RGB.r = t;
RGB.g = p;
RGB.b = v;
}
else {
RGB.r = v;
RGB.g = p;
RGB.b = q;
}
}
dst = pixel4(RGB.r, RGB.g, RGB.b, 1);
}
}
}
Таким образом, принцип прост: конвертируйте каждый пиксель в цветовое пространство HSV, проверьте, попадает ли оттенок между выбранным диапазоном, меняет ли он свой цвет на определенный и конвертирует обратно в RGB.
Проблема в том, что при использовании в приложении Air я не получаю те же результаты, начиная с точки использования только параметров фильтра по умолчанию.
Это код приложения Air:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
width="1400" height="800" backgroundAlpha="0.0" xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="windowedapplication1_creationCompleteHandler(event)">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.events.ColorPickerEvent;
import mx.events.FlexEvent;
import spark.filters.ShaderFilter;
import spark.utils.BitmapUtil;
[Embed(source="myFilter.pbj", mimeType="application/octet-stream")]
private var MyBender:Class;
private var shader:Shader = new Shader();
private var shaderJob:ShaderJob;
private var shaderResult:BitmapData;
private function filter():void
{
// Configure desired input parameters of shader.
shader.data.src.input = originalImage.bitmapData;
// shader.data.HUE.value = [H_slider.value];
// shader.data.SAT.value = [S_slider.value];
// shader.data.VAL.value = [V_slider.value];
// shader.data.MAX_RANGE.value = [H_max_slider.value];
// shader.data.MIN_RANGE.value = [H_min_slider.value];
shaderJob = new ShaderJob(shader, shaderResult);
shaderJob.start(true);
bendedImage.source = new Bitmap(shaderResult);
}
private function windowedapplication1_creationCompleteHandler(event:FlexEvent):void
{
// Create new shader instance and initialize with embedded byte code.
shader = new Shader(new MyBender());
shaderResult = new BitmapData(originalImage.width, originalImage.height);
filter();
}
]]>
</fx:Script>
<s:HGroup width="100%">
<s:Group id="originalGroup" width="100%">
<s:Image id="originalImage" source="mandelbrot.png"/>
</s:Group>
<s:Group id="bendedGroup" width="100%">
<s:SWFLoader id="bendedImage" source="mandelbrot.png" />
<s:HSlider id="H_slider" minimum="0" maximum="359.9" stepSize="0.1" value="0" change="filter()" width="500" toolTip="HUE"/>
<s:HSlider id="S_slider" minimum="-1" maximum="1" stepSize="0.1" value="0" y="20" change="filter()" width="500" toolTip="SAT"/>
<s:HSlider id="V_slider" minimum="-1" maximum="1" stepSize="0.1" value="0" y="40" change="filter()" width="500" toolTip="VAL"/>
<s:HSlider id="H_max_slider" minimum="0" maximum="360" stepSize="0.1" value="360" y="60" change="filter()" width="500" toolTip="HUE MAX"/>
<s:HSlider id="H_min_slider" minimum="0" maximum="360" stepSize="0.1" value="0" y="80" change="filter()" width="500" toolTip="HUE MIN"/>
</s:Group>
</s:HGroup>
</s:WindowedApplication>
Итак, применение фильтра PixelBender в приложении Air с параметрами по умолчанию дает следующее:
https://stackru.com/images/602e35b64835b86e3490f6bdf051970d1306ab48.png
Но в Pixel Bender Toolkit я вижу это с теми же параметрами:
http://i.imgur.com/LNnCi.png
Изменяя ползунок HUE_MAX в приложении (привязанный к параметру фильтра MAX_RANGE), он не отфильтровывает значения HUE плавно, а вместо этого пороговые значения при HUE_MAX=59,9, где при более низких значениях похоже, что фильтр не применяется, а при HUE_MAX=299,9, где между 60 и 299,9 выглядит так:
https://stackru.com/images/b83399bc826147d2d90848a0585089eba3fce818.png
(извините, новый пользователь)
Есть идеи, что я делаю не так?
3 ответа
min
функция делает все возможное для своих параметров, которые я не могу объяснить. Но проблема решается при использовании
pixel1 minVal = r;
if(g < minVal)
minVal = g;
if(b < minVal)
minVal = b;
вместо
pixel1 minVal = min(min(r, g), b);
В вашем коде AS есть строки, которые устанавливают закомментированные значения параметров. Можете ли вы попробовать комментировать их обратно и установить значения по умолчанию. Значения по умолчанию, которые вы помещаете в файл PB, не устанавливаются автоматически во время выполнения, они просто означают подсказки для пользовательского интерфейса.
У вас есть много сравнений с плавающей точкой в вашем коде PB. Линии как это:
if (maxVal == 0.)
чрезвычайно восприимчивы к ошибкам округления. Я предлагаю использовать что-то вроде этого:
if (abs(maxVal) < epsilon)