Qt开发记录12——功能开发——无损偏转(无损地旋转图像)——由Java语言代码改成Qt的C语言代码

Java语言代码

1、toTrimRotateImg

/**
  * 调整旋转角度
  * @return 调整旋转角度后的图片流
  */
 private Mat toTrimRotateImg(Mat srcImage) {
     try {
         // 无损偏转:参数可以指定0到360度。水平旋转就是180度,垂直旋转是90度或者270度
         if (ScanManageController.correct2 != 0) {
             FileUtil.getMemory("toTrimRotateImg-调整旋转角度开始==》");
             srcImage = ImageHelper.RotateNew_bak(srcImage, ScanManageController.correct2);
             FileUtil.getMemory("toTrimRotateImg-调整旋转角度结束!");
         }
         // 正常偏转:angle:向左偏是1到180度,向右偏是-1到-180度
         if (ScanManageController.correct != 0) {
             FileUtil.getMemory("toTrimRotateImg-调整旋转角度开始==》");
             srcImage = ImageHelper.RotateNew(srcImage, ScanManageController.correct);
             FileUtil.getMemory("toTrimRotateImg-调整旋转角度结束!");
         }
     } catch (Exception e) {
         e.printStackTrace();
     }
     return srcImage;
 }

2、ImageHelper类

package com.cxbdapp.cadre.util;

import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.imgproc.Imgproc;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import static org.opencv.core.Core.BORDER_CONSTANT;

public class ImageHelper {

    /**
     * angel:左偏是1到180度,向右偏是-1到-180度
     * @param srcMat
     * @param angel
     * @return
     */
    public static Mat RotateNew(Mat srcMat, double angel) {
        Mat dst = srcMat.clone();
        Point center = new Point(srcMat.width()/2.0,srcMat.height()/2.0);
        Mat mat1 = Imgproc.getRotationMatrix2D(center, angel, 1.0);
        Imgproc.warpAffine(srcMat,dst,mat1,dst.size(),Imgproc.INTER_NEAREST,BORDER_CONSTANT,new Scalar(255,255,255));
        mat1 = null;
        center = null;
        return dst;
    }

    /**
     * 参数可以指定0到360度。水平旋转就是180度,垂直旋转是90度或者270度
     * @param srcMat
     * @param angel
     * @return
     */
    public static Mat RotateNew_bak(Mat srcMat, double angel) {

        BufferedImage src = ImageDeskew.mat2BufferedImage(srcMat);

        int src_width = src.getWidth(null);
        int src_height = src.getHeight(null);
        // 计算旋转后图片的尺寸
        Rectangle rect_des = CalcRotatedSize(new Rectangle(new Dimension(src_width, src_height)), (int) angel);
        BufferedImage res = null;
        res = new BufferedImage(rect_des.width, rect_des.height, src.getType());
        Graphics2D g2 = res.createGraphics();

        g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);

        g2.setColor(Color.WHITE);
        g2.fillRect(0, 0, rect_des.width, rect_des.height);

        // 进行转换
        g2.translate((rect_des.width - src_width) / 2, (rect_des.height - src_height) / 2);
        g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);

        g2.drawImage(src, null, null);


        g2.dispose();

        byte[] pixels = ( (DataBufferByte) res.getRaster().getDataBuffer()).getData();

        // Create a Matrix the same size of image
        Mat I = new Mat(res.getHeight(), res.getWidth(), CvType.CV_8UC3);
        // Fill Matrix with image values
        I.put(0, 0, pixels);

        g2  = null;
        src  = null;
        rect_des = null;
        res = null;

        return I;
    }

    /**
     * 计算旋转后的图片
     *
     * @param src   被旋转的图片
     * @param angel 旋转角度
     * @return 旋转后的图片
     */
    public static Rectangle CalcRotatedSize(Rectangle src, int angel) {
        // 如果旋转的角度大于90度做相应的转换
        if (angel >= 90) {
            if (angel / 90 % 2 == 1) {
                int temp = src.height;
                src.height = src.width;
                src.width = temp;
            }
            angel = angel % 90;
        }

        double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2;
        double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
        double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2;
        double angel_dalta_width = Math.atan((double) src.height / src.width);
        double angel_dalta_height = Math.atan((double) src.width / src.height);

        int len_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha
                - angel_dalta_width));
        int len_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha
                - angel_dalta_height));
        int des_width = src.width + len_dalta_width * 2;
        int des_height = src.height + len_dalta_height * 2;
        return new Rectangle(new Dimension(des_width, des_height));
    }

}

3、ImageDeskew类

package com.cxbdapp.cadre.util;

import org.opencv.core.Mat;
import java.awt.image.BufferedImage;

public class ImageDeskew {
    public static BufferedImage mat2BufferedImage(Mat mat) {
        int cols = mat.cols();
        int rows = mat.rows();
        int elemSize = (int) mat.elemSize();
        byte[] data = new byte[cols * rows * elemSize];
        int type;
        mat.get(0, 0, data);
        switch (mat.channels()) {
            case 1:
                type = BufferedImage.TYPE_BYTE_GRAY;
                break;
            case 3:
                type = BufferedImage.TYPE_3BYTE_BGR;
                // bgr to rgb
                byte b;
                for (int i = 0; i < data.length; i = i + 3) {
                    b = data[i];
                    data[i] = data[i + 2];
                    data[i + 2] = b;
                }
                break;
            default:
                return null;
        }
        BufferedImage image = new BufferedImage(cols, rows, type);
        image.getRaster().setDataElements(0, 0, cols, rows, data);
        return image;
    }
}

C语言代码

1、effect.cpp中


#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>
#include <opencv2/opencv.hpp>
#include <QDir>
#include <QFile>
#include <QPainter>

#include "effect.h"
#include "src/utils/utils.h"

static const double PI = 3.14159265358979323846;
static double toRadians(double degrees) {
    return degrees * PI / 180;
}

/**
 * @brief 旋转缩放
 */
void Effect::RotateZoom(_RotateZoom *rotate, Mat &dst)
{
    dst = m_src.clone();
    if (rotate->noloss_angle != 0) {
        printLog("======无损偏转开始======");
        int noloss_angle = rotate->noloss_angle;
        if (noloss_angle >= 360) {
            noloss_angle = noloss_angle - 360;
        }
        if (noloss_angle < 0) {
            noloss_angle = 360 + noloss_angle;
        }

        QPixmap pixmap = rotatePic(Mat2Pixmap(m_src), noloss_angle);

        // 如果"C:\\SCANFILES"不存在,则创建该文件夹
        QString firDir;
        firDir = "C:\\SCANFILES";
        if (!QFile::exists(firDir))
        {
            QDir dir;
            dir.mkdir(firDir);
        }
        QString fileName = "C:\\SCANFILES\\targetPixmap.jpg";
        pixmap.save(fileName);
        dst = imread(ws2s(fileName.toStdWString()));
        printLog("======无损偏转结束======");
    }
    if (rotate->angle != 0) {
        printLog("======正常偏转开始======");
        int angle = - (rotate->angle);
        // 旋转缩放前的旧图宽高
        int width=m_src.cols, height=m_src.rows;
        if (rotate->noloss_angle != 0) {
            width=dst.cols;
            height=dst.rows;
        }
        // 旋转缩放后的新图尺寸
        Mat M = Mat(2, 3, CV_32FC1);
        // 图像旋转函数:参数含义-旋转中心、旋转度数、缩放比例
        M = getRotationMatrix2D(Point(width/2,height/2),angle,rotate->scale);
        // 图像偏移量
        M.at<double>(0,2) += rotate->x*width;
        M.at<double>(1,2) += rotate->y*height;
        // 利用变换矩阵M对图像进行如旋转、仿射、平移等变换操作
        if (rotate->noloss_angle != 0) {
            warpAffine(dst,dst,M,Size(width,height),INTER_LINEAR,BORDER_CONSTANT,Scalar(255,255,255));
        } else {
            warpAffine(m_src,dst,M,Size(width,height),INTER_LINEAR,BORDER_CONSTANT,Scalar(255,255,255));
        }
        printLog("======正常偏转结束======");
    } else {
        if (rotate->scale != 1.0) {
            rotate = new _RotateZoom(0,0,0,0,0,0,rotate->scale,false);

            // 旋转缩放前的旧图宽高
            int width = dst.cols, height = dst.rows;
            // 旋转缩放后的新图尺寸
            Mat M = Mat(2, 3, CV_32FC1);
            // 图像旋转函数:参数含义-旋转中心、旋转度数、缩放比例
            M = getRotationMatrix2D(Point(width/2,height/2),rotate->angle,rotate->scale);
            // 图像偏移量
            M.at<double>(0,2) += rotate->x*width;
            M.at<double>(1,2) += rotate->y*height;
            // 利用变换矩阵M对图像进行如旋转、仿射、平移等变换操作
            warpAffine(dst,dst,M,Size(width,height),INTER_LINEAR,BORDER_CONSTANT,Scalar(255,255,255));
        }
    }
}

QPixmap Effect::rotatePic(QPixmap srcPixmap, int angle)
{
    printLog("无损偏转算法函数 Effect::rotatePic angle=" + QString::number(angle));

    int src_width = srcPixmap.width();
    int src_height = srcPixmap.height();
    QRect targetRect;
    QRect sourceRect(0,0,srcPixmap.width(), srcPixmap.height());
    printLog("计算旋转后图片的尺寸");
    targetRect = calcRotatedSize(sourceRect, angle);
    QPixmap targetPixmap(targetRect.width(), targetRect.height());
    QPainter p(&targetPixmap); // 创建画家对象
    printLog("设置渲染,启动反锯齿(即反走样。反走样的效果其实比不走样要好得多,反走样是一种比较复杂的算法,在一些对图像质量要求不高的应用中,是不需要进行反走样的。为了提高效率,一般的图形绘制系统,如Java2D、OpenGL之类都是默认不进行反走样的。)");
    p.setRenderHint(QPainter::Antialiasing, true);
    printLog("对指定的矩形区域填充颜色");
    p.fillRect(0, 0, targetRect.width(), targetRect.height(), Qt::white);
    printLog("进行转换");
    p.translate(targetRect.width() / 2, targetRect.height() / 2);
    printLog("进行旋转");
    p.rotate(angle);
    printLog("绘制图形");
    p.drawPixmap(-src_width/2, -src_height/2, srcPixmap);

    return targetPixmap.scaled(src_width, src_height);
}

QRect Effect::calcRotatedSize(QRect sourceRect, int angle)
{
    printLog("1计算旋转后图片的尺寸:(" + QString::number(sourceRect.x()) + ", " + QString::number(sourceRect.y()) + ", " + QString::number(sourceRect.width()) + ", " + QString::number(sourceRect.height()) + ")");
    if (angle >= 90) {
        if (angle / 90 % 2 == 1) {
            int temp = sourceRect.height();
            sourceRect.setHeight(sourceRect.width());
            sourceRect.setWidth(temp);
        }
        angle = angle % 90;
    }

    double r = sqrt(sourceRect.height() * sourceRect.height() + sourceRect.width() * sourceRect.width()) / 2;
    double len = 2 * sin(toRadians(angle) / 2) * r;
    double angle_alpha = (PI - toRadians(angle)) / 2;
    double angle_dalta_width = atan((double) sourceRect.height() / sourceRect.width());
    double angle_dalta_height = atan((double) sourceRect.width() / sourceRect.height());

    int len_dalta_width = (int) (len * cos(PI - angle_alpha - angle_dalta_width));
    int len_dalta_height = (int) (len * cos(PI - angle_alpha - angle_dalta_height));
    int des_width = sourceRect.width() + len_dalta_width * 2;
    int des_height = sourceRect.height() + len_dalta_height * 2;

    QPoint topleft, bottomright;
    topleft.setX(0);
    topleft.setY(0);
    bottomright.setX(des_width);
    bottomright.setY(des_height);
    QRect rect(topleft, bottomright);
    printLog("2计算旋转后图片的尺寸:(" + QString::number(rect.x()) + ", " + QString::number(rect.y()) + ", " + QString::number(rect.width()) + ", " + QString::number(rect.height()) + ")");
    return rect;
}

2、effect.h中

#ifndef EFFECT_H
#define EFFECT_H

#include "src/utils/types.h"
#include <opencv2/core/core.hpp>
#include <QImage>

using namespace cv;

class Effect
{
public:
    Effect(void);
    ~Effect(void);

public:
    // 正常旋转-平移-缩放
    void RotateZoom(_RotateZoom *rotate, cv::Mat &dst);
    // 无损偏转算法函数
    QPixmap rotatePic(QPixmap srcPixmap, int angle);
    // 计算旋转后图片的尺寸
    QRect calcRotatedSize(QRect sourceRect, int angle);

private:
    cv::Mat m_src;
//    cv::Mat m_mask;
};

#endif // EFFECT_H

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小言W

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值