Chromatic Aberration¶
The Chromatic Aberration kernel is a pixel-wise kernel that approximately simulates chromatic aberration artefacts.
The kernel applies two chromatic aberration artefacts:
Transverse Aberration - occurs when the different wavelengths of light are defracted through the lens and hit the sensor at different locations. This is most observable at the edges of images.
Axial Aberration - occurs when the red and blue wavelengths of light do not focus on the image sensor. This usually occurs with very short depth of fields.
The Axial Blur Size Sets how much blur should be applied to the red and blue channels. Effectively, a higher blur is setting a greater distance between the wavelengths’ focus points and the sensor.
The Transverse Colour Shifts set how much each colour channel should be offset by the STMap image.
/// Chromatic Aberration kernel: A simple approximation of transverse and axial chromatic aberration effects.
kernel ChromaticAberration : ImageComputationKernel<ePixelWise>
{
Image<eRead, eAccessRandom, eEdgeClamped> src;
Image<eRead, eAccessPoint> edgeMask;
Image<eRead, eAccessPoint> stMap;
Image<eWrite, eAccessPoint> dst;
param:
bool enableAxial;
bool enableTransverse;
int axialBlurSize;
float4 transverseAmounts;
void define() {
defineParam(enableAxial, "Enable Axial Aberration", true);
defineParam(axialBlurSize, "Axial Blur Size", 5);
defineParam(enableTransverse, "Enable Transverse Aberration", true);
defineParam(transverseAmounts, "Transverse Colour Shifts", float4(0.001f, 0.0005f, 0.0002f, 0.0f));
}
void process(int2 pos) {
SampleType(src) sourceColour = src(pos.x, pos.y);
// Transverse Chromatic Aberration:
// Sample from the lens distortion STMap and lerp between
// the original pixel position and the distorted position.
SampleType(stMap) uv = stMap();
float2 aberPos(uv.x * src.bounds.width(), uv.y * src.bounds.height());
float2 fPos(pos);
float2 redPos(fPos);
float2 greenPos(fPos);
float2 bluePos(fPos);
if (enableTransverse) {
// find the interpolated pixel positions for each channel
// based on the transverse offset amounts
redPos = lerp(fPos, aberPos, transverseAmounts.x);
greenPos = lerp(fPos, aberPos, transverseAmounts.y);
bluePos = lerp(fPos, aberPos, transverseAmounts.z);
sourceColour.x = bilinear(src, redPos.x, redPos.y, 0);
sourceColour.y = bilinear(src, greenPos.x, greenPos.y, 1);
sourceColour.z = bilinear(src, bluePos.x, bluePos.y, 2);
}
// Axial Chromatic Aberration:
// Using an edge detection as a mask, blur the red and green channels
// to simulate axial chromatic aberration
if (enableAxial && axialBlurSize > 0) {
float2 blurredRB(0.f);
float numSamples = 4 * axialBlurSize * axialBlurSize;
for (int i = -axialBlurSize; i < axialBlurSize; i++) {
for (int j = -axialBlurSize; j < axialBlurSize; j++) {
blurredRB.x += bilinear(src, redPos.x+i, redPos.y+j, 0);
blurredRB.y += bilinear(src, bluePos.x+i, bluePos.y+j, 2);
}
}
blurredRB /= numSamples;
// Apply the blur to the red and blue channels based on our mask
float mask = edgeMask(0);
sourceColour.x = lerp(blurredRB.x, sourceColour.x, mask);
sourceColour.z = lerp(blurredRB.y, sourceColour.z, mask);
}
SampleType(dst) output(0);
output.x = sourceColour.x;
output.y = sourceColour.y;
output.z = sourceColour.z;
dst() = output;
}
};