人脸美颜等功能

package com.example.opencvapplication;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class Expt_7 extends AppCompatActivity {

    private Bitmap select_bitmap;
    private double max_size = 1024;
    private ImageView img_expt_7;
    private CascadeClassifier faceDetector;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_expt7);

        //初始化加载OpenCV
        OpenCVLoader.initDebug();
        Button button_go_home7 = findViewById(R.id.go_home7);

        //添加按钮点击响应
        button_go_home7.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //界面跳转
                startActivity(new Intent(Expt_7.this,MainActivity.class));
            }
        });//
        Button btn_imgLoad_7 = findViewById(R.id.btn_imgLoad_7);
        Button btn_faceBeauty = findViewById(R.id.btn_faceBeauty);
        Button btn_restore_7 = findViewById(R.id.btn_restore_7);
        img_expt_7 = findViewById(R.id.img_expt_7);

        btn_imgLoad_7.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 打开文件选择器
                Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
                intent.addCategory(Intent.CATEGORY_OPENABLE);
                //指定只显示图片
                intent.setType("image/*");
                // 实现跳转
                fromAlbumDataLauncher.launch(intent);
            }
        });

        btn_restore_7.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Bitmap bitmap = select_bitmap.copy(select_bitmap.getConfig(), true);
                img_expt_7.setImageBitmap(bitmap);
            }
        });

        btn_faceBeauty.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                //构建Bitmap类型对象,拷贝载入的图片
                Bitmap bitmap = select_bitmap.copy(select_bitmap.getConfig(), true);
                //原图像RGBA类型
                Mat src = new Mat();
                Utils.bitmapToMat(bitmap, src);
                Imgproc.cvtColor(src, src, Imgproc.COLOR_RGBA2RGB);
                //目标图像,美颜后的图像
                Mat dst = new Mat(src.size(),src.type());
                //高斯双边滤波
                Imgproc.bilateralFilter(src,dst,0,150,10);
                //生成遮罩层
                Mat mask = generateMask(src);

                //对mask实现高斯模糊
                Imgproc.cvtColor(mask,mask,Imgproc.COLOR_RGBA2GRAY);
                Imgproc.GaussianBlur(mask, mask,new Size( 3, 3),0,0,
                        Core.BORDER_DEFAULT);

                //mask模糊图像转换类型,归一化
                Mat blur_mask =new Mat();
                mask.convertTo(blur_mask,CvType.CV_32F);
                Core.normalize(blur_mask,blur_mask, 1.0,0,Core.NORM_MINMAX);
                //根据归一化后的模版完成高斯融合
                GaussianAdd(src,dst,blur_mask);

                // 边缘提升
                Mat border =new Mat();
                Mat temp_mat = new Mat();
                //获取图像上的边缘(此时图像上的边缘为白色)
                Imgproc.Canny(src,border,50,150,3,true);

                //将图像边缘的色彩通过与计算賦值给temp_mat
                Core.bitwise_and(dst,dst,temp_mat,border);
                Core.addWeighted(dst,0.9,temp_mat,0.1,0, dst);

                //亮度提升
                Core.add(dst,new Scalar(40,40,40),dst);

                Utils.matToBitmap(dst,bitmap);
                img_expt_7.setImageBitmap(bitmap);

                //释放内存
                src.release();
                dst.release();
                mask.release();
                blur_mask.release();
                border.release();
                temp_mat.release();
            }
        });

    }

    //注册对Activity结果的监听
    //新建一个ActivityResultLauncher对象,使用该对象的launch方法来实现跳转
    //并且另一个活动结束时会回调该对象registerForActivityResult()方法,我们在回调的时获取并执行数据
    private ActivityResultLauncher fromAlbumDataLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {
                @Override
                public void onActivityResult(ActivityResult result) {

                    if (result.getResultCode() == RESULT_OK && result.getData() != null) {
                        //Uri代表要操作的数据,Android上可用的资源(图像、视频片段)
                        Uri uri = result.getData().getData();
                        if (uri != null) {
                            //将选择的图片显示
                            try {
                                //读取图片并进行降采样
                                select_bitmap = getBitmapFromUri(uri);
                            } catch (FileNotFoundException e) {
                                e.printStackTrace();
                            }
                        }
                        if (select_bitmap != null) {
                            //图像关联实现窗口
                            img_expt_7.setImageBitmap(select_bitmap);
                        }
                    }
                }
            });

    private Bitmap getBitmapFromUri(Uri uri) throws FileNotFoundException {

        Bitmap bitmap_temp = null;
        //使用ContentResolver通过uri打开输入流
        InputStream input = getContentResolver().openInputStream(uri);
        // options.inJustDecodeBounds = true;
        // 这时候decode的bitmap为null,只是把图片的高度放在Option里
        // 避免大图片溢出问题
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(input, null, options);
        //---------图像将采样,限制载入图像的大小-------
        int raw_width = options.outWidth;
        int raw_height = options.outHeight;
        Log.i("Image-tag", "Image size:" + raw_height + " " + raw_width);
        int max = Math.max(raw_height, raw_width);
        int new_width = raw_width;
        int new_height = raw_height;
        int inSampleSize = 1;
        if (max > max_size) {
            new_width = raw_width;
            new_height = raw_height;
            //设置合适的压缩比例inSampleSize
            while ((new_width / inSampleSize) > max_size || (new_height / inSampleSize) > max_size) {
                inSampleSize *= 2;
            }
        }
        //设置合适的缩放比例,将options。inJustDecodeBounds = false
        //重新读出图片
        options.inSampleSize = inSampleSize;
        options.inJustDecodeBounds = false;
        // 表示每个通道占8位,总计4个字节
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
        bitmap_temp = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
        Log.i("Image-tag-1", "Image size: " + bitmap_temp.getHeight() + " " + bitmap_temp.getWidth());
        return bitmap_temp;
    }

    private Mat generateMask(Mat src) {
        //获取图像的通道数,宽度,高度,用于遍历图像像素
        int channels = src.channels();
        int width = src.cols();
        int height = src.rows();
        int B = 0, G = 0, R = 0;
        byte[] data = new byte[width * height * channels];
        //将src中的数据存入data
        src.get(0, 0, data);
        //遍历data中的所有元素
        for (int i = 0; i < data.length; i++) {
            if (0 == i % channels) {
                //获取像素的RGB三通道数
                R = data[i] & 0xff;
                G = data[i + 1] & 0xff;
                B = data[i + 2] & 0xff;
                //判断是否是皮肤区域
                if (R > 95 && 6 > 40 && B > 20 && (Math.max(R, Math.max(G, B)) - Math.min(R, Math.min(R, B))) > 15
                        && Math.abs(R - G) > 15 && R > G && R > B) {
                    data[i] = (byte) 255;
                    data[i + 1] = (byte) 255;
                    data[i + 2] = (byte) 255;
                }
            }
        }
        Mat dst = new Mat(src.size(), src.type());
        dst.put(0, 0, data);
        return dst;
    }

    private void GaussianAdd(Mat src,Mat dst,Mat blur_mask){

        int width = src.cols();
        int height = src.rows();
        int channels = src.channels();

        byte[] data_1 = new byte[width*height*channels];
        byte[] data_2 = new byte[width*height*channels];
        float[] mask_data = new float[width*height];

        blur_mask.get(0,0,mask_data);
        src.get(0,0,data_1);
        dst.get(0,0,data_2);

        for(int row = 0;row<height;row++){
            for(int col = 0;col<width;col++){
                int r1 = data_1[row*channels*width+col*channels]&0xff;
                int g1 = data_1[row*channels*width+col*channels+1]&0xff;
                int b1 = data_1[row*channels*width+col*channels+2]&0xff;

                int r2 = data_2[row*channels*width+col*channels]&0xff;
                int g2 = data_2[row*channels*width+col*channels+1]&0xff;
                int b2 = data_2[row*channels*width+col*channels+2]&0xff;

                float w2 = mask_data[row*width+col];
                float w1 = 1.0f-w2;

                r2 = (int) (r2*w2+w1*r1);
                g2 = (int) (g2*w2+w1*g1);
                b2 = (int) (b2*w2+w1*b1);

                data_2[row*channels*width+col*channels] = (byte) r2;
                data_2[row*channels*width+col*channels+1] = (byte) g2;
                data_2[row*channels*width+col*channels+2] = (byte) b2;
            }
        }
        dst.put(0,0,data_2);
    }
}

内容概要:本文详细探讨了杯形谐波减速器的齿廓修形方法及寿命预测分析。文章首先介绍了针对柔轮与波发生器装配时出现的啮合干涉问题,提出了一种柔轮齿廓修形方法。通过有限元法装配仿真确定修形量,并对修形后的柔轮进行装配和运转有限元分析。基于Miner线性疲劳理论,使用Fe-safe软件预测柔轮寿命。结果显示,修形后柔轮装配最大应力从962.2 MPa降至532.7 MPa,负载运转应力为609.9 MPa,解决了啮合干涉问题,柔轮寿命循环次数达到4.28×10⁶次。此外,文中还提供了详细的Python代码实现及ANSYS APDL脚本,用于柔轮变形分析、齿廓修形设计、有限元验证和疲劳寿命预测。 适合人群:机械工程领域的研究人员、工程师,尤其是从事精密传动系统设计和分析的专业人士。 使用场景及目标:①解决杯形谐波减速器中柔轮与波发生器装配时的啮合干涉问题;②通过优化齿廓修形提高柔轮的力学性能和使用寿命;③利用有限元分析和疲劳寿命预测技术评估修形效果,确保设计方案的可靠性和可行性。 阅读建议:本文涉及大量有限元分析和疲劳寿命预测的具体实现细节,建议读者具备一定的机械工程基础知识和有限元分析经验。同时,读者可以通过提供的Python代码和ANSYS APDL脚本进行实际操作和验证,加深对修形方法和技术路线的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值