美文网首页
BufferedImage与Opencv cv::Mat互相转换

BufferedImage与Opencv cv::Mat互相转换

作者: 愤怒的桑树 | 来源:发表于2020-03-04 15:53 被阅读0次

    最近遇到一个需求,要把在C中通过opencv渲染的图像,通过jni传到java,再由java层创建BufferedImage并展示。
    流程如下:

    1. 通过java读取图片为BufferedImage

    // 这里加入了使用exif信息修正图片位置的代码
    private static BufferedImage readImg(String path) {
            File img = new File(path);
            if (!img.exists()) {
                return null;
            }
    
            Metadata metadata = null;
            BufferedImage read = null;
            try {
                read = ImageIO.read(img);
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (read == null) {
                    return null;
                }
                metadata = ImageMetadataReader.readMetadata(img);
    
                ExifIFD0Directory directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
                int width = read.getWidth();
                int height = read.getHeight();
                if (directory != null) {
                    int orientation = 1;
                    try {
                        orientation = directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
                        AffineTransform affineTransform = new AffineTransform();
    
                        switch (orientation) {
                            case 1:
                                break;
                            case 2: // Flip X
                                affineTransform.scale(-1.0, 1.0);
                                affineTransform.translate(-width, 0);
                                break;
                            case 3: // PI rotation
                                affineTransform.translate(width, height);
                                affineTransform.rotate(Math.PI);
                                break;
                            case 4: // Flip Y
                                affineTransform.scale(1.0, -1.0);
                                affineTransform.translate(0, -height);
                                break;
                            case 5: // - PI/2 and Flip X
                                affineTransform.rotate(-Math.PI / 2);
                                affineTransform.scale(-1.0, 1.0);
                                break;
                            case 6: // -PI/2 and -width
                                affineTransform.translate(height, 0);
                                affineTransform.rotate(Math.PI / 2);
                                break;
                            case 7: // PI/2 and Flip
                                affineTransform.scale(-1.0, 1.0);
                                affineTransform.translate(-height, 0);
                                affineTransform.translate(0, width);
                                affineTransform.rotate(3 * Math.PI / 2);
                                break;
                            case 8: // PI / 2
                                affineTransform.translate(0, width);
                                affineTransform.rotate(3 * Math.PI / 2);
                                break;
                            default:
                                break;
                        }
    
                        AffineTransformOp affineTransformOp = new AffineTransformOp(affineTransform, AffineTransformOp.TYPE_BILINEAR);
                        BufferedImage destinationImage = new BufferedImage(read.getHeight(), read.getWidth(), read.getType());
                        destinationImage = affineTransformOp.filter(read, destinationImage);
                        return destinationImage;
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
                return read;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
    
        }
    

    2. 将图片转换为int数组

    java中int为32位,颜色划分每八位分割,这个算法在C层会再次用到:

    // 颜色组合有可能是ARGB, RGBA, ABGR, ARGB
    // 如果需要将RGB转换为ARGB或RGBA,那么只需要在对应A通道上写入255即可
    channel1 = (char) ((val >> 24) & 0xFF);
    channel2 = (char) ((val >> 16) & 0xFF);
    channel3 = (char) ((val >> 8) & 0xFF);
    channel4 = (char) (val & 0xFF);
    

    3. 将该数组传入jni层,并通过jni方法转换为C层可用的形式,(这里选用参数方式传递数据)

    jint *const RGB_i = (env->GetIntArrayElements(java_rgb_array, &JNI_FALSE));
    

    4. 创建cv::Mat

    jint在jni_md.h中的定义就是int,所以这里可以直接强转使用(是否有更安全的办法)
    CV_8UC4意思是:输入数组是8位无符号整型,4通道

    cv::Mat src(input_img_height, input_img_width, CV_8UC4, (unsigned int*)RGB_i);
    

    5. 将cv::Mat中的data成员变量(即储存图片颜色信息的数组),转换为bufferedImage接受的格式

    // 这里转换为RGB格式数组
    void matToBitmapArray(const cv::Mat &image, jint*_data) {
        // BGR format
        for (int i = 0; i < image.total(); i ++) {
            char r = image.data[3 * i + 2];
            char g = image.data[3 * i + 1];
            char b = image.data[3 * i + 0];
            _data[i] = (((jint)r << 16) & 0x00FF0000) +
                (((jint)g << 8) & 0x0000FF00) + ((jint)b & 0x000000FF);
        }
    }
    

    6. 将该数组拷贝回jvm(依然通过参数方式传递)

    env->SetIntArrayRegion(outputBuffer, 0, width*height, _data);
    

    7. 在java中,创建BufferedImage

    // 这里注意TYPE_INT_RGB对应在jni层创建的RGB格式int数组
    BufferedImage destImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    destImg.setRGB(0, 0, width, height, _data, 0, width);
    

    相关文章

      网友评论

          本文标题:BufferedImage与Opencv cv::Mat互相转换

          本文链接:https://www.haomeiwen.com/subject/jlwvlhtx.html