Overview
The BadPixelProcessor library is designed to detect and correct bad pixels on video from thermal cameras (LWIR, MWIR, and SWIR). The working principle: the library takes RAW images. When the first video frame comes to the library, it reads the config file with the list of bad pixel coordinates and initializes the internal buffer. If the config file contains bad pixel coordinates, the library replaces such pixels with mean values of neighbor pixels. Also, the library automatically detects bad pixels on video after a user command and stores coordinates in the config file. To detect bad pixels, the user must provide flat surfaces that cover the field of view of the camera. In addition, the library performs an image flip operation if necessary. The library accepts video frames only with YUV24 pixel format (see Frame class description). The library uses only the Y (brightness) component of YUV24 pixels. The library is implemented in C++ (C++17 standard) and does not have third-party dependencies to be installed in the system. Each instance of the BadPixelProcessor C++ class object performs frame-by-frame processing of a video data stream, processing each video frame independently. The bad pixel detection and correction algorithm works only on one CPU core. The library depends on the open-source VFilter library (provides an interface and defines data structures for various video filter implementations, source code included, Apache 2.0 license). Additionally, the example application depends on OpenCV (provides user interface, version >= 4.5, linked, Apache 2.0 license). The library is compatible with Linux and Windows.
Downloads
Documentation: GO TO DOCUMENTATION
Simple interface
class BadPixelProcessor : public VFilter
{
public:
/// Get string of current library version.
static std::string getVersion();
/// Initialize filter.
bool initVFilter(VFilterParams& params) override;
/// Set filter parameter.
bool setParam(VFilterParam id, float value) override;
/// Get filter parameter value.
float getParam(VFilterParam id) override;
/// Get all filter parameters.
void getParams(VFilterParams& params) override;
/// Execute action command.
bool executeCommand(VFilterCommand id) override;
/// Process frame.
bool processFrame(cr::video::Frame& frame) override;
/// Set filter mask. Not supported in current version.
bool setMask(cr::video::Frame mask) override;
/// Decode and execute command.
bool decodeAndExecuteCommand(uint8_t* data, int size) override;
/// Set path to config file with bad pixels coordinates.
void setBadPixelsConfigFilePath(std::string path);
};
Simple example
#include <opencv2/opencv.hpp>
#include "BadPixelProcessor.h"
int main(void)
{
// Prepare bad pixel processor filter parameters.
cr::video::VFilterParams filterParams;
filterParams.mode = 1; // Enable filter.
filterParams.level = 20.0f; // Set neighborhood difference threshold.
filterParams.custom1 = 20.0f; // Set low pixel threshold.
filterParams.custom2 = 235.0f; // Set high pixel threshold.
// Create bad pixel processor filter.
cr::video::BadPixelProcessor filter;
if (!filter.initVFilter(filterParams))
{
std::cout << "Error initializing BadPixelProcessor filter\n";
return -1;
}
// Set path to config file.
filter.setBadPixelsConfigFilePath("badPixelsConfig.json");
// Frame size.
const int width = 1280;
const int height = 1024;
// Create frame.
cr::video::Frame srcFrameYuv(width, height, cr::video::Fourcc::YUV24);
// Main loop.
uint8_t pixelValue = 0;
int frameCounter = 0;
int pixelsOffset = 20;
while (true)
{
// Fill frame by value.
memset(srcFrameYuv.data, 128, srcFrameYuv.size);
for (int i = 0; i < srcFrameYuv.size; i = i + 3)
srcFrameYuv.data[i] = pixelValue;
++pixelValue;
// Add two bad pixels: one black and one white.
srcFrameYuv.data[pixelsOffset * width * 3 + 50 * 3] = 0;
srcFrameYuv.data[pixelsOffset * 2 * width * 3 + 60 * 3] = 255;
srcFrameYuv.data[pixelsOffset * 3 * width * 3 + 70 * 3] = 0;
srcFrameYuv.data[pixelsOffset * 4 * width * 3 + 80 * 3] = 255;
srcFrameYuv.data[pixelsOffset * 5 * width * 3 + 90 * 3] = 0;
// Process frame.
filter.processFrame(srcFrameYuv);
// Get all filter parameters.
filter.getParams(filterParams);
// Convert to BGR.
cv::Mat imgYuv(height, width, CV_8UC3, srcFrameYuv.data);
cv::Mat imgBgr;
cv::cvtColor(imgYuv, imgBgr, cv::COLOR_YUV2BGR);
// Display frame.
cv::imshow("BadPixelProcessor Example", imgBgr);
switch (cv::waitKey(30))
{
case 27: // ESC key.
return 0;
case 32: // SPACE key.
// Start detection of bad pixels.
filter.executeCommand(cr::video::VFilterCommand::RESET);
break;
case 13: // ENTER key - enable / disable filter.
if (filterParams.mode == 1)
filter.setParam(cr::video::VFilterParam::MODE, 0);
else
filter.setParam(cr::video::VFilterParam::MODE, 1);
break;
case 102: // F key - Image flip mode change.
case 70: // f key
{
int currentFlipMode = (int)filter.getParam(cr::video::VFilterParam::CUSTOM_3);
currentFlipMode = (currentFlipMode + 1) % 4;
filter.setParam(cr::video::VFilterParam::CUSTOM_3, (float)currentFlipMode);
}
break;
case 114: // R key - increase pixels offset
case 82: // r key
{
pixelsOffset += 2;
break;
}
}
}
return 1;
}

