You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

109 lines
4.0 KiB
TypeScript

// Copyright (C) 2021-2022 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) {
throw new Error(e.toString());
} 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(),
});
}
}