javascript - 如何使用opencv4node.js设置矩阵区域

标签 javascript node.js opencv matrix opencv4nodejs

问题:

在opencv4nodejs中设置矩阵区域的最快方法是什么?

问题:

我将源图像叠加到较大的目标图像中,而尺寸却低至数千。

在Python中,我将通过以下方式获取/设置大小匹配的区域:

destination[y:y+h, x:x+w] = source[:,:]

但是我不确定如何在Javascript中执行此操作。

我尝试了几种方法,但是即使最快,也非常慢。

例如,我有:
  • source_mat cols:2929,行:2049
  • dest_mat cols:3000,行数:6000
  • offset_x:150,offset_y:150

  • 将矩阵转换为数组,循环行和列,设置目标像素大约需要12秒
    let debug_overlay_start = new Date().valueOf();
    let source_pixels = source_mat.getDataAsArray();
    for (let row_index = 0, l_1 = source_pixels.length; row_index < l_1; row_index++) {
        if(row_index + offset_y < 0) continue;
        if(row_index + offset_y >= dest_mat.rows) continue;
        let this_col = source_pixels[row_index];
        for (let col_index = 0, l_2 = this_col.length; col_index < l_2; col_index++) {
            if(col_index + offset_x < 0) continue;
            if(col_index + offset_x >= dest_mat.cols) continue;
            dest_mat.set(row_index + offset_y, col_index + offset_x, source_pixels[row_index][col_index]);
        }
    }
    let debug_overlay_end = new Date().valueOf();
    console.log(`overlay method took ${((debug_overlay_end - debug_overlay_start)/1000).toFixed(2)}`); // overlay method took  11.63
    return dest_mat;
    

    将它们都转换为数组,遍历行,拼接cols耗时82秒:
    let debug_overlay_end = new Date().valueOf();
    let source_pixels = source_mat.getDataAsArray();
    let new_dest_mat = dest_mat.getDataAsArray();
    for (let row_index = 0, l_1 = source_pixels.length; row_index < l_1; row_index++) {
        if(row_index + offset_y < 0) continue;
        if(row_index + offset_y >= dest_mat.rows) continue;
        let this_col = source_pixels[row_index]; // entire column of source pixels
        new_dest_mat[row_index + offset_y].splice(offset_x, this_col.length, ...this_col);
    }
    let debug_overlay_end = new Date().valueOf();
    console.log(`overlay method took ${((debug_overlay_end - debug_overlay_start)/1000).toFixed(2)}`); // 82 seconds
    return new cv.Mat(new_dest_mat, dest_mat.type);
    

    替换区域根本不起作用,在没有其他日志记录的情况下引发了生命周期错误:
    let debug_overlay_end = new Date().valueOf();
    let area_to_replace = dest_mat.getRegion(new cv.Rect(x, y, source_mat.cols, source_mat.rows));
    area_to_replace = source_mat.getRegion(new cv.Rect(0, 0, source_mat.cols, source_mat.rows)); // lifecycle error
    console.log(`overlay method took ${((debug_overlay_end - debug_overlay_start)/1000).toFixed(2)}`);
    return dest_mat;
    

    到目前为止,使用setAt()atRaw()最快速度为8秒:
    let debug_overlay_start = new Date().valueOf();
    for(let row_index = 0, row_length = source_mat.rows; row_index < row_length; row_index++){
        if(row_index + offset_y < 0) continue;
        if(row_index + offset_y >= dest_mat.rows) continue;
        for(let col_index = 0, col_length = source_mat.cols; col_index < col_length; col_index++){
            if(col_index + offset_x < 0) continue;
            if(col_index + offset_x >= dest_mat.cols) continue;
            dest_mat.set(row_index + offset_y, col_index + offset_x, source_mat.atRaw(row_index, col_index));
        }
    }
    let debug_overlay_end = new Date().valueOf();
    console.log(`overlay method took ${((debug_overlay_end - debug_overlay_start)/1000).toFixed(2)}`); // 8.09
    return dest_mat;
    

    我看了看文档,很惊讶地看到这不是一个普通的用例。节点/电子环境是否会减慢本应快速的运行速度?

    最佳答案

    使用缓冲区阵列设法降低到1.1秒。不确定如何加快速度。

    /**
     * Places a source matrix onto a dest matrix.
     * Note: This replaces pixels entirely, it doesn't merge transparency
     * @param {cv.Mat} source_mat matrix being copied
     * @param {cv.Mat} dest_mat matrix being pasted into
     * @param {number} x horizontal offset of source image
     * @param {number} y vertical offset of source image
     */
    function overlayOnto(source_mat, dest_mat, x, y){
        if(source_mat.channels != dest_mat.channels) throw new Error('src and dst channel counts must match');
        let source_uint8 = new Uint8Array( source_mat.getData() ); // WARNING 4 CHANNELS
        let dest_uint8 = new Uint8Array( dest_mat.getData() ); // WARNING 4 CHANNELS
        let dest_width = dest_mat.cols;
        let x_count = 0; // set counters
        let y_count = 0; // set counters
        let channel_count = source_mat.channels;
        for (let i = 0; i < source_uint8.length; i += channel_count) { // WARNING 4 CHANNELS
            let dest_x = x_count + x; // add offset
            let dest_y = y_count + y; // add offset
    
            if( !( (dest_x < 0 || dest_x > dest_mat.cols-1) || (dest_y < 0 || dest_y > dest_mat.rows-1) ) ){ // pixel does not fall outside of dest mat
                // write into buffer array
                let dest_i = (dest_x + dest_width * dest_y); // (x + w * h) to get x/y coord in single-dimension array
                let dest_buffer_i = dest_i * channel_count;
                if(channel_count >= 1)  dest_uint8.fill(source_uint8[i+0], dest_buffer_i+0 , dest_buffer_i+0+1);
                if(channel_count >= 2)  dest_uint8.fill(source_uint8[i+1], dest_buffer_i+1 , dest_buffer_i+1+1);
                if(channel_count >= 3)  dest_uint8.fill(source_uint8[i+2], dest_buffer_i+2 , dest_buffer_i+2+1);
                if(channel_count >= 4)  dest_uint8.fill(source_uint8[i+3], dest_buffer_i+3 , dest_buffer_i+3+1);
            }
            x_count++; // increase col
            x_count = x_count % source_mat.cols; // end of col? move to start
            if(x_count == 0) y_count++; // started new col? increase row 
        }
        return new cv.Mat(dest_uint8, dest_mat.rows, dest_mat.cols, dest_mat.type);
    }
    

    关于javascript - 如何使用opencv4node.js设置矩阵区域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57699414/

    相关文章:

    python - 提取二值图像中的最中心区域

    python - 实现多处理以在 opencv 中同时测试两个视频以进行对象检测

    javascript - 从 Node.js 中的文件同步读取行

    node.js - 使用 nodejs 和/或 hapijs 提供静态文件 - 路由

    javascript - 当我给 PHP 变量赋值时,是否可以调用 JavaScript 函数?

    javascript - 如何使用 popmotion pure 从关键帧旋转、平移和缩放矩形?

    node.js - 使用 nodemailer 从 node.js 应用程序发送电子邮件

    python - 为什么我不能调整 PNG 文件的亮度级别

    javascript - 定位元素失败

    javascript - 检查值是否在 ng-repeat 内 ng-if 的数组中