Writing an Imagepipeline Plugin

From LuxCoreRender Wiki
Revision as of 09:28, 2 December 2017 by Byob (talk | contribs)
Jump to navigation Jump to search

C++ Code

Files that need to be created:

  • Header: include/slg/film/imagepipeline/plugins/yourpluginname.h
  • Source: src/slg/film/imagepipeline/plugins/yourpluginname.cpp

Files that need to be edited:

  • Filmparse: src/slg/film/filmparse.cpp
  • CMakeLists.txt: src/slg/CMakeLists.txt

Example: OverExposureDetection Plugin

As an exmaple for this tutorial, we'll write a plugin that sets the pixel color to red when it detects pixels which are brighter than a specified threshold. The threshold can be specified by the user in the .cfg file.

Header File

Create a new header file with filepath include/slg/film/imagepipeline/plugins/overexposuredetection.h

/***************************************************************************
 * Copyright 1998-2017 by authors (see AUTHORS.txt)                        *
 *                                                                         *
 *   This file is part of LuxRender.                                       *
 *                                                                         *
 * Licensed under the Apache License, Version 2.0 (the "License");         *
 * you may not use this file except in compliance with the License.        *
 * You may obtain a copy of the License at                                 *
 *                                                                         *
 *     http://www.apache.org/licenses/LICENSE-2.0                          *
 *                                                                         *
 * Unless required by applicable law or agreed to in writing, software     *
 * distributed under the License is distributed on an "AS IS" BASIS,       *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*
 * See the License for the specific language governing permissions and     *
 * limitations under the License.                                          *
 ***************************************************************************/

#ifndef _SLG_OVEREXPOSUREDETECTION_H
#define	_SLG_OVEREXPOSUREDETECTION_H

#include <vector>
#include <memory>
#include <typeinfo>
#include <boost/serialization/version.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/vector.hpp>

#include "eos/portable_oarchive.hpp"
#include "eos/portable_iarchive.hpp"

#include "luxrays/luxrays.h"
#include "luxrays/core/color/color.h"
#include "luxrays/core/oclintersectiondevice.h"
#include "slg/film/imagepipeline/imagepipeline.h"

namespace slg {

//------------------------------------------------------------------------------
// OverExposureDetection plugin
//------------------------------------------------------------------------------

class OverExposureDetection : public ImagePipelinePlugin {
public:
	OverExposureDetection(float threshold);
	virtual ~OverExposureDetection() {};

	virtual ImagePipelinePlugin *Copy() const;

	virtual void Apply(Film &film, const u_int index);

	friend class boost::serialization::access;

private:
	OverExposureDetection();

	template<class Archive> void serialize(Archive &ar, const u_int version) {
		ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(ImagePipelinePlugin);
		// TODO: implement serialization for ImageMap
		throw std::runtime_error("OverExposureDetection serialization not yet supported");
	}

	float threshold;
};

}

BOOST_CLASS_VERSION(slg::OverExposureDetection, 1)

BOOST_CLASS_EXPORT_KEY(slg::OverExposureDetection)

#endif	/* _SLG_OVEREXPOSUREDETECTION_H */

Source File

Create a new source file with filepath src/slg/film/imagepipeline/plugins/overexposuredetection.cpp

/***************************************************************************
 * Copyright 1998-2017 by authors (see AUTHORS.txt)                        *
 *                                                                         *
 *   This file is part of LuxRender.                                       *
 *                                                                         *
 * Licensed under the Apache License, Version 2.0 (the "License");         *
 * you may not use this file except in compliance with the License.        *
 * You may obtain a copy of the License at                                 *
 *                                                                         *
 *     http://www.apache.org/licenses/LICENSE-2.0                          *
 *                                                                         *
 * Unless required by applicable law or agreed to in writing, software     *
 * distributed under the License is distributed on an "AS IS" BASIS,       *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*
 * See the License for the specific language governing permissions and     *
 * limitations under the License.                                          *
 ***************************************************************************/

#include <stdexcept>
#include <boost/foreach.hpp>
#include <boost/regex.hpp>

#include "luxrays/kernels/kernels.h"
#include "slg/kernels/kernels.h"
#include "slg/film/film.h"
#include "slg/film/imagepipeline/plugins/overexposuredetection.h"

using namespace std;
using namespace luxrays;
using namespace slg;

//------------------------------------------------------------------------------
// OverExposureDetection plugin
//------------------------------------------------------------------------------

BOOST_CLASS_EXPORT_IMPLEMENT(slg::OverExposureDetection)

OverExposureDetection::OverExposureDetection(float threshold)
	: threshold(threshold)
{}

OverExposureDetection::OverExposureDetection()
	: threshold(1000.f)
{}

ImagePipelinePlugin *OverExposureDetection::Copy() const {
	return new OverExposureDetection(threshold);
}

//------------------------------------------------------------------------------
// CPU version
//------------------------------------------------------------------------------

#if _OPENMP >= 200805
	typedef unsigned int itertype;
#else
	// Visual C++ 2013 supports only OpenMP 2.5
	typedef int itertype;
#endif

void OverExposureDetection::Apply(Film &film, const u_int index) {
	Spectrum *pixels = (Spectrum *)film.channel_IMAGEPIPELINEs[index]->GetPixels();
	const u_int pixelCount = film.GetWidth() * film.GetHeight();

	#pragma omp parallel for
	for (itertype i = 0; i < pixelCount; ++i) {
		if (*(film.channel_FRAMEBUFFER_MASK->GetPixel(index))) {
			const float brightness = pixels[i].Y();
			
			if(brightness > threshold) {
				pixels[i].c[0] = 1.f;
				pixels[i].c[1] = 0.f;
				pixels[i].c[2] = 0.f;
			}
		}
	}
}

Modifying Filmparse

Open the file src/slg/film/filmparse.cpp and include your header file, right under the last include line and before the "using namespace x" lines.

#include "slg/film/imagepipeline/plugins/overexposuredetection.h"

In the same file, go to the function Film::AllocImagePipeline. You'll see a long if/else if/... section where the plugins are initialized. Add an else if clause at the end, before the final else:

    // ...
} else if (type == "OVEREXPOSURE_DETECTION") {
    const float threshold = Clamp(props.Get(Property(prefix + ".threshold")(1000.f)).Get<float>(), 0.f, INFINITY);
    imagePipeline->AddPlugin(new OverExposureDetection(threshold));
} else
    // ...

The string for the type == "PLUGINNAME" comparison can be chosen freely (it does not occur in any other files). By convention it should be all upper case, with underscores for better readability in long names.

Next, parse the value that the user set for the "threshold" parameter in the .cfg configuration file of a luxcore scene definition. Our plugin is configured like this:

# Film image pipeline plug-ins
film.imagepipeline.0.type = TONEMAP_LINEAR
film.imagepipeline.1.type = GAMMA_CORRECTION
film.imagepipeline.1.value = 2.2

# Our plugin: detect overexposure after all other imagepipeline operations are done
# Note that after a tonemap operation, all colors are in 0..1 range
film.imagepipeline.2.type = OVEREXPOSURE_DETECTION
film.imagepipeline.2.threshold = 0.99

However, the user can also omit the film.imagepipeline.2.threshold = ... line if we define a default value in the filmparse function.

It is also a good idea to sanitize the input with a Clamp function. In our case, a threshold below 0 does not make sense.

Modifying CMakeLists.txt

Open src/slg/CMakeLists.txt Search for set(SLG_FILM_SRCS and add your source filepath among the other imagepipeline plugins:

${LuxRays_SOURCE_DIR}/src/slg/film/imagepipeline/plugins/overexposuredetection.cpp

Compile

To test your plugin, compile LuxCore: Compiling_LuxCore

OpenCL Code

ImagePipeline plugins can be accelerated with OpenCL. However, I don't know how to do this yet, so I'm leaving this section blank for now.