You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Java OpenCV旋转图像时像素颜色异常变化问题求助

问题解决:OpenCV旋转图像后颜色失真

核心问题原因

  • 重复JPG有损压缩:当前代码在BufferedImage和Mat转换时,反复使用JPG格式编码解码。JPG是有损压缩格式,每一次转换都会丢失像素细节,多次旋转后颜色失真会越来越严重。
  • 颜色空间不匹配:OpenCV默认使用BGR颜色通道顺序,而JavaFX/Swing的BufferedImage采用RGB顺序,直接转换会导致颜色反转(比如蓝色变红色)。

修正后的代码

替换原有转换方法并调整旋转逻辑,避免有损压缩并修正颜色空间:

package application;

import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.IOException;

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgproc.Imgproc;

import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;

public class SampleController {

    @FXML
    private ImageView myimageview;
    
    @FXML
    private Button showimageButton, rotateButton;

    @FXML
    void rotateButtonClicked(ActionEvent event) throws Exception {
        BufferedImage image = SwingFXUtils.fromFXImage(myimageview.getImage(), null);    
        Mat src = BufferedImage2Mat(image);        
        // 将RGB转为OpenCV默认的BGR颜色空间
        Imgproc.cvtColor(src, src, Imgproc.COLOR_RGB2BGR);
        Core.rotate(src, src, Core.ROTATE_90_CLOCKWISE);
        // 转换回RGB颜色空间适配JavaFX显示
        Imgproc.cvtColor(src, src, Imgproc.COLOR_BGR2RGB);
        image = Mat2BufferedImage(src);
        try {
            Image converted_image = SwingFXUtils.toFXImage(image, null);
            myimageview.setImage(converted_image);
        }
        catch (Exception e) {
            System.out.println(e);
        }
    }
    
    // 直接通过像素数组转换BufferedImage到Mat,避免JPG编码
    public Mat BufferedImage2Mat(BufferedImage image) {
        Mat mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC3);
        byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
        mat.put(0, 0, data);
        return mat;
    }
    
    // 直接通过像素数组转换Mat到BufferedImage,避免JPG解码
    static BufferedImage Mat2BufferedImage(Mat matrix) {
        int type = BufferedImage.TYPE_3BYTE_BGR;
        // 处理灰度图像的情况
        if (matrix.channels() == 1) {
            type = BufferedImage.TYPE_BYTE_GRAY;
        }
        byte[] buffer = new byte[matrix.channels() * matrix.cols() * matrix.rows()];
        matrix.get(0, 0, buffer);
        BufferedImage image = new BufferedImage(matrix.cols(), matrix.rows(), type);
        final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
        System.arraycopy(buffer, 0, targetPixels, 0, buffer.length);
        return image;
    }
    
    @FXML
    void showimageButtonClicked(ActionEvent event) {
        Image im = new Image("file:///C:\\Users\\poste\\eclipse-workspace\\dragImage\\Images\\temp.jpg");
        myimageview.setImage(im);
    }

}

关键修改说明

  1. 移除JPG编码解码步骤:新的转换方法直接操作底层像素数组,完全避免了有损压缩带来的颜色损失。
  2. 颜色空间适配:在旋转前后添加Imgproc.cvtColor转换,让OpenCV处理BGR格式,转换回RGB后再给JavaFX显示,解决颜色反转问题。
  3. 支持灰度图像:转换方法中增加了灰度图像的判断,兼容单通道图像的转换。

内容的提问来源于stack exchange,提问作者Mouad_thf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 22:40:28