diff options
Diffstat (limited to 'source/blender/compositor')
12 files changed, 911 insertions, 0 deletions
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index cfaf11c4400..fbe391a554d 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -330,6 +330,17 @@ set(SRC operations/COM_KeyingScreenOperation.cpp operations/COM_KeyingScreenOperation.h + nodes/COM_KeyingNode.cpp + nodes/COM_KeyingNode.h + operations/COM_KeyingOperation.cpp + operations/COM_KeyingOperation.h + operations/COM_KeyingBlurOperation.cpp + operations/COM_KeyingBlurOperation.h + operations/COM_KeyingDespillOperation.cpp + operations/COM_KeyingDespillOperation.h + operations/COM_KeyingClipOperation.cpp + operations/COM_KeyingClipOperation.h + operations/COM_ColorSpillOperation.cpp operations/COM_ColorSpillOperation.h operations/COM_RenderLayersBaseProg.cpp diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp index 082e2fe5d04..9731555039c 100644 --- a/source/blender/compositor/intern/COM_Converter.cpp +++ b/source/blender/compositor/intern/COM_Converter.cpp @@ -113,6 +113,7 @@ #include "COM_CropNode.h" #include "COM_MaskNode.h" #include "COM_KeyingScreenNode.h" +#include "COM_KeyingNode.h" Node *Converter::convert(bNode *bNode) { @@ -355,6 +356,9 @@ case CMP_NODE_OUTPUT_FILE: case CMP_NODE_KEYINGSCREEN: node = new KeyingScreenNode(bNode); break; + case CMP_NODE_KEYING: + node = new KeyingNode(bNode); + break; /* not inplemented yet */ default: node = new MuteNode(bNode); diff --git a/source/blender/compositor/nodes/COM_KeyingNode.cpp b/source/blender/compositor/nodes/COM_KeyingNode.cpp new file mode 100644 index 00000000000..74af25b8e5f --- /dev/null +++ b/source/blender/compositor/nodes/COM_KeyingNode.cpp @@ -0,0 +1,227 @@ +/* + * Copyright 2012, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + * Sergey Sharybin + */ + +#include "COM_KeyingNode.h" + +#include "COM_ExecutionSystem.h" + +#include "COM_KeyingOperation.h" +#include "COM_KeyingBlurOperation.h" +#include "COM_KeyingDespillOperation.h" +#include "COM_KeyingClipOperation.h" + +#include "COM_SeparateChannelOperation.h" +#include "COM_CombineChannelsOperation.h" +#include "COM_ConvertRGBToYCCOperation.h" +#include "COM_ConvertYCCToRGBOperation.h" +#include "COM_GaussianBokehBlurOperation.h" +#include "COM_SetValueOperation.h" + +#include "COM_DilateErodeOperation.h" + +#include "COM_SetAlphaOperation.h" + +KeyingNode::KeyingNode(bNode *editorNode): Node(editorNode) +{ +} + +OutputSocket *KeyingNode::setupPreBlur(ExecutionSystem *graph, InputSocket *inputImage, int size, OutputSocket **originalImage) +{ + ConvertRGBToYCCOperation *convertRGBToYCCOperation = new ConvertRGBToYCCOperation(); + convertRGBToYCCOperation->setMode(0); /* ITU 601 */ + + inputImage->relinkConnections(convertRGBToYCCOperation->getInputSocket(0), 0, graph); + graph->addOperation(convertRGBToYCCOperation); + + CombineChannelsOperation *combineOperation = new CombineChannelsOperation(); + graph->addOperation(combineOperation); + + for (int channel = 0; channel < 4; channel++) { + SeparateChannelOperation *separateOperation = new SeparateChannelOperation(); + separateOperation->setChannel(channel); + addLink(graph, convertRGBToYCCOperation->getOutputSocket(0), separateOperation->getInputSocket(0)); + graph->addOperation(separateOperation); + + if (channel == 0 || channel == 3) { + addLink(graph, separateOperation->getOutputSocket(0), combineOperation->getInputSocket(channel)); + } + else { + KeyingBlurOperation *blurOperation = new KeyingBlurOperation(); + + blurOperation->setSize(size); + + addLink(graph, separateOperation->getOutputSocket(0), blurOperation->getInputSocket(0)); + addLink(graph, blurOperation->getOutputSocket(0), combineOperation->getInputSocket(channel)); + graph->addOperation(blurOperation); + } + } + + ConvertYCCToRGBOperation *convertYCCToRGBOperation = new ConvertYCCToRGBOperation(); + convertYCCToRGBOperation->setMode(0); /* ITU 601 */ + addLink(graph, combineOperation->getOutputSocket(0), convertYCCToRGBOperation->getInputSocket(0)); + graph->addOperation(convertYCCToRGBOperation); + + *originalImage = convertRGBToYCCOperation->getInputSocket(0)->getConnection()->getFromSocket(); + + return convertYCCToRGBOperation->getOutputSocket(0); +} + +OutputSocket *KeyingNode::setupPostBlur(ExecutionSystem *graph, OutputSocket *postBLurInput, int size) +{ + KeyingBlurOperation *blurOperation = new KeyingBlurOperation(); + + blurOperation->setSize(size); + + addLink(graph, postBLurInput, blurOperation->getInputSocket(0)); + + graph->addOperation(blurOperation); + + return blurOperation->getOutputSocket(); +} + +OutputSocket *KeyingNode::setupDilateErode(ExecutionSystem *graph, OutputSocket *dilateErodeInput, int distance) +{ + DilateStepOperation *dilateErodeOperation; + + if (distance > 0) { + dilateErodeOperation = new DilateStepOperation(); + dilateErodeOperation->setIterations(distance); + } + else { + dilateErodeOperation = new ErodeStepOperation(); + dilateErodeOperation->setIterations(-distance); + } + + addLink(graph, dilateErodeInput, dilateErodeOperation->getInputSocket(0)); + + graph->addOperation(dilateErodeOperation); + + return dilateErodeOperation->getOutputSocket(0); +} + +OutputSocket *KeyingNode::setupDespill(ExecutionSystem *graph, OutputSocket *despillInput, OutputSocket *inputScreen, float factor) +{ + KeyingDespillOperation *despillOperation = new KeyingDespillOperation(); + + despillOperation->setDespillFactor(factor); + + addLink(graph, despillInput, despillOperation->getInputSocket(0)); + addLink(graph, inputScreen, despillOperation->getInputSocket(1)); + + graph->addOperation(despillOperation); + + return despillOperation->getOutputSocket(0); +} + +OutputSocket *KeyingNode::setupClip(ExecutionSystem *graph, OutputSocket *clipInput, int kernelRadius, float kernelTolerance, + float clipBlack, float clipWhite, bool edgeMatte) +{ + KeyingClipOperation *clipOperation = new KeyingClipOperation(); + + clipOperation->setKernelRadius(kernelRadius); + clipOperation->setKernelTolerance(kernelTolerance); + + clipOperation->setClipBlack(clipBlack); + clipOperation->setClipWhite(clipWhite); + clipOperation->setIsEdgeMatte(edgeMatte); + + addLink(graph, clipInput, clipOperation->getInputSocket(0)); + + graph->addOperation(clipOperation); + + return clipOperation->getOutputSocket(0); +} + +void KeyingNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context) +{ + InputSocket *inputImage = this->getInputSocket(0); + InputSocket *inputScreen = this->getInputSocket(1); + OutputSocket *outputImage = this->getOutputSocket(0); + OutputSocket *outputMatte = this->getOutputSocket(1); + OutputSocket *outputEdges = this->getOutputSocket(2); + OutputSocket *postprocessedMatte, *postprocessedImage, *originalImage, *edgesMatte; + + bNode *editorNode = this->getbNode(); + NodeKeyingData *keying_data = (NodeKeyingData *) editorNode->storage; + + /* keying operation */ + KeyingOperation *keyingOperation = new KeyingOperation(); + + keyingOperation->setScreenBalance(keying_data->screen_balance); + + inputScreen->relinkConnections(keyingOperation->getInputSocket(1), 1, graph); + + if (keying_data->blur_pre) { + /* chroma preblur operation for input of keying operation */ + OutputSocket *preBluredImage = setupPreBlur(graph, inputImage, keying_data->blur_pre, &originalImage); + addLink(graph, preBluredImage, keyingOperation->getInputSocket(0)); + } + else { + inputImage->relinkConnections(keyingOperation->getInputSocket(0), 0, graph); + originalImage = keyingOperation->getInputSocket(0)->getConnection()->getFromSocket(); + } + + graph->addOperation(keyingOperation); + + postprocessedMatte = keyingOperation->getOutputSocket(); + + if (keying_data->clip_black > 0.0f || keying_data->clip_white< 1.0f) { + postprocessedMatte = setupClip(graph, postprocessedMatte, + keying_data->edge_kernel_radius, keying_data->edge_kernel_tolerance, + keying_data->clip_black, keying_data->clip_white, false); + } + + edgesMatte = setupClip(graph, postprocessedMatte, + keying_data->edge_kernel_radius, keying_data->edge_kernel_tolerance, + keying_data->clip_black, keying_data->clip_white, true); + + /* apply blur on matte if needed */ + if (keying_data->blur_post) + postprocessedMatte = setupPostBlur(graph, postprocessedMatte, keying_data->blur_post); + + /* matte dilate/erode */ + if (keying_data->dilate_distance != 0) { + postprocessedMatte = setupDilateErode(graph, postprocessedMatte, keying_data->dilate_distance); + } + + /* set alpha channel to output image */ + SetAlphaOperation *alphaOperation = new SetAlphaOperation(); + addLink(graph, originalImage, alphaOperation->getInputSocket(0)); + addLink(graph, postprocessedMatte, alphaOperation->getInputSocket(1)); + + postprocessedImage = alphaOperation->getOutputSocket(); + + /* despill output image */ + if (keying_data->despill_factor > 0.0f) { + postprocessedImage = setupDespill(graph, postprocessedImage, + keyingOperation->getInputSocket(1)->getConnection()->getFromSocket(), + keying_data->despill_factor); + } + + /* connect result to output sockets */ + outputImage->relinkConnections(postprocessedImage); + outputMatte->relinkConnections(postprocessedMatte); + outputEdges->relinkConnections(edgesMatte); + + graph->addOperation(alphaOperation); +} diff --git a/source/blender/compositor/nodes/COM_KeyingNode.h b/source/blender/compositor/nodes/COM_KeyingNode.h new file mode 100644 index 00000000000..cc1d447c66e --- /dev/null +++ b/source/blender/compositor/nodes/COM_KeyingNode.h @@ -0,0 +1,42 @@ +/* + * Copyright 2012, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + * Sergey Sharybin + */ + +#include "COM_Node.h" + +/** + * @brief KeyingNode + * @ingroup Node + */ +class KeyingNode : public Node { +protected: + OutputSocket *setupPreBlur(ExecutionSystem *graph, InputSocket *inputImage, int size, OutputSocket **originalImage); + OutputSocket *setupPostBlur(ExecutionSystem *graph, OutputSocket *postBLurInput, int size); + OutputSocket *setupDilateErode(ExecutionSystem *graph, OutputSocket *dilateErodeInput, int distance); + OutputSocket *setupDespill(ExecutionSystem *graph, OutputSocket *despillInput, OutputSocket *inputSrceen, float factor); + OutputSocket *setupClip(ExecutionSystem *graph, OutputSocket *clipInput, int kernelRadius, float kernelTolerance, + float clipBlack, float clipWhite, bool edgeMatte); +public: + KeyingNode(bNode *editorNode); + void convertToOperations(ExecutionSystem *graph, CompositorContext *context); + +}; diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp b/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp new file mode 100644 index 00000000000..3ed3921e0c1 --- /dev/null +++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp @@ -0,0 +1,88 @@ +/* + * Copyright 2012, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + * Sergey Sharybin + */ + +#include "COM_KeyingBlurOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" + +KeyingBlurOperation::KeyingBlurOperation(): NodeOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VALUE); + + this->size = 0.0f; + + this->setComplex(true); +} + +void *KeyingBlurOperation::initializeTileData(rcti *rect, MemoryBuffer **memoryBuffers) +{ + void *buffer = getInputOperation(0)->initializeTileData(rect, memoryBuffers); + + return buffer; +} + +void KeyingBlurOperation::executePixel(float *color, int x, int y, MemoryBuffer *inputBuffers[], void *data) +{ + MemoryBuffer *inputBuffer = (MemoryBuffer*)data; + float *buffer = inputBuffer->getBuffer(); + + int bufferWidth = inputBuffer->getWidth(); + int bufferHeight = inputBuffer->getHeight(); + + int i, j, count = 0; + + float average = 0.0f; + + for (i = -this->size + 1; i < this->size; i++) { + for (j = -this->size + 1; j < this->size; j++) { + int cx = x + j, cy = y + i; + + if (cx >= 0 && cx < bufferWidth && cy >= 0 && cy < bufferHeight) { + int bufferIndex = (cy * bufferWidth + cx) * 4; + + average += buffer[bufferIndex]; + count++; + } + } + } + + average /= (float) count; + + color[0] = average; +} + +bool KeyingBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + rcti newInput; + + newInput.xmin = 0; + newInput.ymin = 0; + newInput.xmax = this->getWidth(); + newInput.ymax = this->getHeight(); + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.h b/source/blender/compositor/operations/COM_KeyingBlurOperation.h new file mode 100644 index 00000000000..8d7834c7265 --- /dev/null +++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.h @@ -0,0 +1,48 @@ +/* + * Copyright 2012, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + * Sergey Sharybin + */ + +#ifndef _COM_KeyingBlurOperation_h +#define _COM_KeyingBlurOperation_h + +#include "COM_NodeOperation.h" + +/** + * Class with implementation of bluring for keying node + */ +class KeyingBlurOperation : public NodeOperation { +protected: + int size; + +public: + KeyingBlurOperation(); + + void setSize(float value) {this->size = value;} + + void *initializeTileData(rcti *rect, MemoryBuffer **memoryBuffers); + + void executePixel(float *color, int x, int y, MemoryBuffer *inputBuffers[], void *data); + + bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output); +}; + +#endif diff --git a/source/blender/compositor/operations/COM_KeyingClipOperation.cpp b/source/blender/compositor/operations/COM_KeyingClipOperation.cpp new file mode 100644 index 00000000000..09b5b7a523c --- /dev/null +++ b/source/blender/compositor/operations/COM_KeyingClipOperation.cpp @@ -0,0 +1,123 @@ +/* + * Copyright 2012, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + * Sergey Sharybin + */ + +#include "COM_KeyingClipOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" + +KeyingClipOperation::KeyingClipOperation(): NodeOperation() +{ + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_VALUE); + + this->kernelRadius = 3; + this->kernelTolerance = 0.1f; + + this->clipBlack = 0.0f; + this->clipWhite = 1.0f; + + this->isEdgeMatte = false; + + this->setComplex(true); +} + +void *KeyingClipOperation::initializeTileData(rcti *rect, MemoryBuffer **memoryBuffers) +{ + void *buffer = getInputOperation(0)->initializeTileData(rect, memoryBuffers); + + return buffer; +} + +void KeyingClipOperation::executePixel(float *color, int x, int y, MemoryBuffer *inputBuffers[], void *data) +{ + const int delta = this->kernelRadius; + const float tolerance = this->kernelTolerance; + + MemoryBuffer *inputBuffer = (MemoryBuffer*)data; + float *buffer = inputBuffer->getBuffer(); + + int bufferWidth = inputBuffer->getWidth(); + int bufferHeight = inputBuffer->getHeight(); + + int i, j, count = 0, totalCount = 0; + + float value = buffer[(y * bufferWidth + x) * 4]; + + bool ok = false; + + for (i = -delta + 1; i < delta; i++) { + for (j = -delta + 1; j < delta; j++) { + int cx = x + j, cy = y + i; + + if (i == 0 && j == 0) + continue; + + if (cx >= 0 && cx < bufferWidth && cy >= 0 && cy < bufferHeight) { + int bufferIndex = (cy * bufferWidth + cx) * 4; + float currentValue = buffer[bufferIndex]; + + if (fabsf(currentValue - value) < tolerance) { + count++; + } + + totalCount++; + } + } + } + + ok = count >= (float) totalCount * 0.9f; + + if (this->isEdgeMatte) { + if (ok) + color[0] = 0.0f; + else + color[0] = 1.0f; + } + else { + color[0] = value; + + if (ok) { + if (color[0] < this->clipBlack) + color[0] = 0.0f; + else if (color[0] >= this->clipWhite) + color[0] = 1.0f; + else + color[0] = (color[0] - this->clipBlack) / (this->clipWhite - this->clipBlack); + } + } +} + +bool KeyingClipOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + rcti newInput; + + newInput.xmin = 0; + newInput.ymin = 0; + newInput.xmax = this->getWidth(); + newInput.ymax = this->getHeight(); + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} diff --git a/source/blender/compositor/operations/COM_KeyingClipOperation.h b/source/blender/compositor/operations/COM_KeyingClipOperation.h new file mode 100644 index 00000000000..9c7b23b0160 --- /dev/null +++ b/source/blender/compositor/operations/COM_KeyingClipOperation.h @@ -0,0 +1,59 @@ +/* + * Copyright 2012, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + * Sergey Sharybin + */ + +#ifndef _COM_KeyingClipOperation_h +#define _COM_KeyingClipOperation_h + +#include "COM_NodeOperation.h" + +/** + * Class with implementation of black/white clipping for keying node + */ +class KeyingClipOperation : public NodeOperation { +protected: + float clipBlack; + float clipWhite; + + int kernelRadius; + float kernelTolerance; + + bool isEdgeMatte; +public: + KeyingClipOperation(); + + void setClipBlack(float value) {this->clipBlack = value;} + void setClipWhite(float value) {this->clipWhite = value;} + + void setKernelRadius(int value) {this->kernelRadius = value;} + void setKernelTolerance(float value) {this->kernelTolerance = value;} + + void setIsEdgeMatte(bool value) {this->isEdgeMatte = value;} + + void *initializeTileData(rcti *rect, MemoryBuffer **memoryBuffers); + + void executePixel(float *color, int x, int y, MemoryBuffer *inputBuffers[], void *data); + + bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output); +}; + +#endif diff --git a/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp b/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp new file mode 100644 index 00000000000..b7fd2772729 --- /dev/null +++ b/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp @@ -0,0 +1,89 @@ +/* + * Copyright 2012, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + * Sergey Sharybin + */ + +#include "COM_KeyingDespillOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" + +static int get_pixel_primary_channel(float *pixel) +{ + float max_value = MAX3(pixel[0], pixel[1], pixel[2]); + + if (max_value == pixel[0]) + return 0; + else if (max_value == pixel[1]) + return 1; + + return 2; +} + +KeyingDespillOperation::KeyingDespillOperation(): NodeOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + + this->despillFactor = 0.5f; + + this->pixelReader = NULL; + this->screenReader = NULL; +} + +void KeyingDespillOperation::initExecution() +{ + this->pixelReader = this->getInputSocketReader(0); + this->screenReader = this->getInputSocketReader(1); +} + +void KeyingDespillOperation::deinitExecution() +{ + this->pixelReader = NULL; + this->screenReader = NULL; +} + +void KeyingDespillOperation::executePixel(float *color, float x, float y, PixelSampler sampler, MemoryBuffer *inputBuffers[]) +{ + float pixelColor[4]; + float screenColor[4]; + + this->pixelReader->read(pixelColor, x, y, sampler, inputBuffers); + this->screenReader->read(screenColor, x, y, sampler, inputBuffers); + + int screen_primary_channel = get_pixel_primary_channel(screenColor); + float average_value, amount; + + average_value = (pixelColor[0] + pixelColor[1] + pixelColor[2] - pixelColor[screen_primary_channel]) / 2.0f; + amount = pixelColor[screen_primary_channel] - average_value; + + color[0] = pixelColor[0]; + color[1] = pixelColor[1]; + color[2] = pixelColor[2]; + color[3] = pixelColor[3]; + + if (this->despillFactor * amount > 0) { + color[screen_primary_channel] = pixelColor[screen_primary_channel] - this->despillFactor * amount; + } +} diff --git a/source/blender/compositor/operations/COM_KeyingDespillOperation.h b/source/blender/compositor/operations/COM_KeyingDespillOperation.h new file mode 100644 index 00000000000..92a1415a1f0 --- /dev/null +++ b/source/blender/compositor/operations/COM_KeyingDespillOperation.h @@ -0,0 +1,49 @@ +/* + * Copyright 2012, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + * Sergey Sharybin + */ + +#ifndef _COM_KeyingDespillOperation_h +#define _COM_KeyingDespillOperation_h + +#include "COM_NodeOperation.h" + +/** + * Class with implementation of keying despill node + */ +class KeyingDespillOperation : public NodeOperation { +protected: + SocketReader *pixelReader; + SocketReader *screenReader; + float despillFactor; + +public: + KeyingDespillOperation(); + + void initExecution(); + void deinitExecution(); + + void setDespillFactor(float value) {this->despillFactor = value;} + + void executePixel(float *color, float x, float y, PixelSampler sampler, MemoryBuffer *inputBuffers[]); +}; + +#endif diff --git a/source/blender/compositor/operations/COM_KeyingOperation.cpp b/source/blender/compositor/operations/COM_KeyingOperation.cpp new file mode 100644 index 00000000000..fba4dc65faf --- /dev/null +++ b/source/blender/compositor/operations/COM_KeyingOperation.cpp @@ -0,0 +1,115 @@ +/* + * Copyright 2012, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + * Sergey Sharybin + */ + +#include "COM_KeyingOperation.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" + +static int get_pixel_primary_channel(float pixelColor[4]) +{ + float max_value = MAX3(pixelColor[0], pixelColor[1], pixelColor[2]); + + if (max_value == pixelColor[0]) + return 0; + else if (max_value == pixelColor[1]) + return 1; + + return 2; +} + +static float get_pixel_saturation(float pixelColor[4], float screen_balance, int primary_channel) +{ + int other_1 = (primary_channel + 1) % 3; + int other_2 = (primary_channel + 2) % 3; + + float min = MIN2(pixelColor[other_1], pixelColor[other_2]); + float max = MAX2(pixelColor[other_1], pixelColor[other_2]); + float val = screen_balance * min + (1.0f - screen_balance) * max; + + return (pixelColor[primary_channel] - val) * fabsf(1.0f - val); +} + +KeyingOperation::KeyingOperation(): NodeOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_VALUE); + + this->screenBalance = 0.5f; + + this->pixelReader = NULL; + this->screenReader = NULL; +} + +void KeyingOperation::initExecution() +{ + this->pixelReader = this->getInputSocketReader(0); + this->screenReader = this->getInputSocketReader(1); +} + +void KeyingOperation::deinitExecution() +{ + this->pixelReader = NULL; + this->screenReader = NULL; +} + +void KeyingOperation::executePixel(float *color, float x, float y, PixelSampler sampler, MemoryBuffer *inputBuffers[]) +{ + float pixelColor[4]; + float screenColor[4]; + + this->pixelReader->read(pixelColor, x, y, sampler, inputBuffers); + this->screenReader->read(screenColor, x, y, sampler, inputBuffers); + + int primary_channel = get_pixel_primary_channel(screenColor); + + float saturation = get_pixel_saturation(pixelColor, this->screenBalance, primary_channel); + float screen_saturation = get_pixel_saturation(screenColor, this->screenBalance, primary_channel); + + if (saturation < 0) { + color[0] = 1.0f; + } + else if (saturation >= screen_saturation) { + color[0] = 0.0f; + } + else { + float distance = 1.0f - saturation / screen_saturation; + + color[0] = distance; + } +} + +bool KeyingOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + rcti newInput; + + newInput.xmin = 0; + newInput.ymin = 0; + newInput.xmax = this->getWidth(); + newInput.ymax = this->getHeight(); + + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} diff --git a/source/blender/compositor/operations/COM_KeyingOperation.h b/source/blender/compositor/operations/COM_KeyingOperation.h new file mode 100644 index 00000000000..0fc13407d14 --- /dev/null +++ b/source/blender/compositor/operations/COM_KeyingOperation.h @@ -0,0 +1,56 @@ +/* + * Copyright 2012, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + * Sergey Sharybin + */ + + +#ifndef _COM_KeyingOperation_h +#define _COM_KeyingOperation_h + +#include <string.h> + +#include "COM_NodeOperation.h" + +#include "BLI_listbase.h" + +/** + * Class with implementation of keying node + */ +class KeyingOperation : public NodeOperation { +protected: + SocketReader *pixelReader; + SocketReader *screenReader; + float screenBalance; + +public: + KeyingOperation(); + + void initExecution(); + void deinitExecution(); + + void setScreenBalance(float value) {this->screenBalance = value;} + + void executePixel(float *color, float x, float y, PixelSampler sampler, MemoryBuffer *inputBuffers[]); + + bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output); +}; + +#endif |