はじめに
OpenCVのドキュメントやサンプルって基本的にC++かPythonなのでJavaScriptでやるときにちょっと調べないといけないんですよね。
私はK-meansやるときにちょっと苦戦したので、備忘録としてやり方載せておきます。
本記事ではK-meansについては解説しませんのであしからず。
FloatをUint8に変換
こうすると若干早くなります。
// Convert Float to UInt8
const floatToUint8 = x => Math.min(Math.max(Math.round(x), 0), 255);
const ui8Centers = new Uint8Array(k * 3);
for(let c = 0; c < k; c += 1) {
for(let z = 0; z < 3; z += 1) {
ui8Centers[c * 3 + z] = floatToUint8(centers.floatAt(c, z));
}
}
centers.delete();
ソース
自作クラスのstatic メソッドを貼り付けておきます。
/**
* Color reduction processing using K-means
* @param {Mat} src source mat
* @param {Mat} dst destination mat
* @param {number} k cluster count
* @param {number} attempts number of attempts
* @param {number} maxCount the maximum number of iterations/elements
* @param {number} epsilon the desired accuracy
* @returns {Mat} destination mat
*/
static kmeans(src, dst, k, attempts, maxCount = 1e4, epsilon = 1e-4) {
// Initialize
dst = dst || new cv.Mat(src.size(), src.type());
const [labels, centers] = [new cv.Mat(), new cv.Mat()];
const criteria = new cv.TermCriteria(cv.TermCriteria_EPS + cv.TermCriteria_MAX_ITER, maxCount, epsilon);
const flags = cv.KMEANS_PP_CENTERS;
// Create samples
const samples = new cv.Mat(src.rows * src.cols, 3, cv.CV_32F);
for(let y = 0; y < src.rows; y += 1) {
for(let x = 0; x < src.cols; x += 1) {
const idx = y * src.cols + x;
for(let z = 0; z < 3; z += 1) {
samples.floatPtr(idx)[z] = src.data[idx * 4 + z];
}
}
}
// K-Means method
let startDate = new Date();
cv.kmeans(samples, k, labels, criteria, attempts, flags, centers);
console.log('kmeans:', new Date() - startDate, 'ms');
// Convert Float to UInt8
const floatToUint8 = x => Math.min(Math.max(Math.round(x), 0), 255);
const ui8Centers = new Uint8Array(k * 3);
for(let c = 0; c < k; c += 1) {
for(let z = 0; z < 3; z += 1) {
ui8Centers[c * 3 + z] = floatToUint8(centers.floatAt(c, z));
}
}
centers.delete();
// Create dst from labels and centers
startDate = new Date();
for(let y = 0; y < dst.rows; y += 1) {
for(let x = 0; x < dst.cols; x += 1) {
const p = (y * dst.cols + x) * 4;
const c = labels.data[p];
for(let z = 0; z < 3; z += 1) {
dst.data[p + z] = ui8Centers[c * 3 + z];
}
dst.data[p + 3] = src.data[p + 3];
}
}
labels.delete();
console.log('after kmeans:', new Date() - startDate, 'ms');
return dst;
}
参考リンク
How can you use K-Means clustering to posterize an image using opencv javascript?