Histogram equalization feature (#3447)
* Added histogram equalization * Fixed equalization memory leak * Removed unused console.log * Fixed eslint errors * Fixed algorithm implementation in opencv control * Fixed histogram equalization disabling * Fixed eslint errors * Removed outdated code and reworked cycles in functions * Fixed forceUpdate flag disabling * Fixed image bitmap creation * Fixed running setState and imageModifiermain
parent
e3616df0da
commit
7e7a5b9623
@ -0,0 +1,109 @@
|
|||||||
|
// Copyright (C) 2021 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import { ImageProcessing } from './opencv-interfaces';
|
||||||
|
|
||||||
|
export interface HistogramEqualization extends ImageProcessing{
|
||||||
|
processImage: (src:ImageData, frameNumber: number)=>ImageData;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HashedImage{
|
||||||
|
frameNumber: number,
|
||||||
|
frameData: ImageData,
|
||||||
|
timestamp: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class HistogramEqualizationImplementation implements HistogramEqualization {
|
||||||
|
private readonly bufferSize: number = 20;
|
||||||
|
private cv:any;
|
||||||
|
private histHash: HashedImage[];
|
||||||
|
public currentProcessedImage: number | undefined;
|
||||||
|
|
||||||
|
constructor(cv:any) {
|
||||||
|
this.cv = cv;
|
||||||
|
this.histHash = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public processImage(src:ImageData, frameNumber: number) : ImageData {
|
||||||
|
const hashedFrame = this.hashedFrame(frameNumber);
|
||||||
|
if (!hashedFrame) {
|
||||||
|
const { cv } = this;
|
||||||
|
let matImage = null;
|
||||||
|
const RGBImage = new cv.Mat();
|
||||||
|
const YUVImage = new cv.Mat();
|
||||||
|
const RGBDist = new cv.Mat();
|
||||||
|
const YUVDist = new cv.Mat();
|
||||||
|
const RGBADist = new cv.Mat();
|
||||||
|
let channels = new cv.MatVector();
|
||||||
|
const equalizedY = new cv.Mat();
|
||||||
|
try {
|
||||||
|
this.currentProcessedImage = frameNumber;
|
||||||
|
matImage = cv.matFromImageData(src);
|
||||||
|
cv.cvtColor(matImage, RGBImage, cv.COLOR_RGBA2RGB, 0);
|
||||||
|
cv.cvtColor(RGBImage, YUVImage, cv.COLOR_RGB2YUV, 0);
|
||||||
|
cv.split(YUVImage, channels);
|
||||||
|
const [Y, U, V] = [channels.get(0), channels.get(1), channels.get(2)];
|
||||||
|
channels.delete();
|
||||||
|
channels = null;
|
||||||
|
cv.equalizeHist(Y, equalizedY);
|
||||||
|
Y.delete();
|
||||||
|
channels = new cv.MatVector();
|
||||||
|
channels.push_back(equalizedY); equalizedY.delete();
|
||||||
|
channels.push_back(U); U.delete();
|
||||||
|
channels.push_back(V); V.delete();
|
||||||
|
cv.merge(channels, YUVDist);
|
||||||
|
cv.cvtColor(YUVDist, RGBDist, cv.COLOR_YUV2RGB, 0);
|
||||||
|
cv.cvtColor(RGBDist, RGBADist, cv.COLOR_RGB2RGBA, 0);
|
||||||
|
const arr = new Uint8ClampedArray(RGBADist.data, RGBADist.cols, RGBADist.rows);
|
||||||
|
const imgData = new ImageData(arr, src.width, src.height);
|
||||||
|
this.hashFrame(imgData, frameNumber);
|
||||||
|
return imgData;
|
||||||
|
} catch (e) {
|
||||||
|
console.log('Histogram equalization error', e);
|
||||||
|
return src;
|
||||||
|
} finally {
|
||||||
|
if (matImage) matImage.delete();
|
||||||
|
if (channels) channels.delete();
|
||||||
|
RGBImage.delete();
|
||||||
|
YUVImage.delete();
|
||||||
|
RGBDist.delete();
|
||||||
|
YUVDist.delete();
|
||||||
|
RGBADist.delete();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.currentProcessedImage = frameNumber;
|
||||||
|
return hashedFrame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private hashedFrame(frameNumber: number): ImageData|null {
|
||||||
|
const hashed = this.histHash.find((_hashed) => _hashed.frameNumber === frameNumber);
|
||||||
|
if (hashed) {
|
||||||
|
hashed.timestamp = Date.now();
|
||||||
|
}
|
||||||
|
return hashed?.frameData || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private hashFrame(frameData:ImageData, frameNumber:number):void{
|
||||||
|
if (this.histHash.length >= this.bufferSize) {
|
||||||
|
const leastRecentlyUsed = this.histHash[0];
|
||||||
|
const currentTimestamp = Date.now();
|
||||||
|
let diff = currentTimestamp - leastRecentlyUsed.timestamp;
|
||||||
|
let leastIndex = 0;
|
||||||
|
for (let i = 1; i < this.histHash.length; i++) {
|
||||||
|
const currentDiff = currentTimestamp - this.histHash[i].timestamp;
|
||||||
|
if (currentDiff > diff) {
|
||||||
|
diff = currentDiff;
|
||||||
|
leastIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.histHash.splice(leastIndex, 1);
|
||||||
|
}
|
||||||
|
this.histHash.push({
|
||||||
|
frameData,
|
||||||
|
frameNumber,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
// Copyright (C) 2021 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
export interface ImageProcessing {
|
||||||
|
processImage: (src: ImageData, frameNumber: number) => ImageData;
|
||||||
|
currentProcessedImage: number|undefined
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 420 KiB |
Loading…
Reference in New Issue