Android+opencv实时人脸与人眼检测案例分享

news2024/9/25 23:22:09

软件版本:

Android Studio Electric Eel 2022.1.1 Patch 2

https://sourceforge.net/projects/opencvlibrary/files/4.5.0/opencv-4.5.0-android-sdk.zip/download

创建工程并导入opencv sdk:

导入opencv sdk:
File->New->Import Module

添加工程依赖:File->Project Structure, sdk为opencv sdk.

导入人脸和人眼检测训练模型

haarcascade_eye_tree_eyeglasses.xml
lbpcascade_frontalface_improved.xml 标题

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>

<org.opencv.android.JavaCameraView
    android:id="@+id/camera_view"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:layout_weight="1"/>

<Button
    android:layout_width="37dp"
    android:layout_height="37dp"
    android:layout_margin="10dp"
    android:layout_gravity="center_vertical"
    android:background="@mipmap/ic_launcher"
    android:id="@+id/switchCamera"/>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>




<application
    android:allowBackup="true"
    android:dataExtractionRules="@xml/data_extraction_rules"
    android:fullBackupContent="@xml/backup_rules"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/Theme.Facedetectwithcamera"
    tools:targetApi="31">
    <activity
        android:name=".MainActivity"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

MainActivity

package com.michael.facedetectwithcamera;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.Toast;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraActivity;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.android.JavaCameraView;
import org.opencv.android.LoaderCallbackInterface;
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.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
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.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends CameraActivity implements View.OnClickListener, CvCameraViewListener2 {
//public class MainActivity extends CameraActivity implements View.OnClickListener {
private static final String TAG = “…OpencvCam…”;
private JavaCameraView cameraView;
private Button switchButton;
private boolean isFrontCamera = true;
private Mat mRgba,leftEye_template,rightEye_template;
private CascadeClassifier classifier, classifierEye;
private static final Scalar EYE_RECT_COLOR = new Scalar(0,0,255);
private int mAbsoluteFaceSize = 0;
// private CameraBridgeViewBase.CvCameraViewListener2 cvCameraViewListener2 = new CameraBridgeViewBase.CvCameraViewListener2() {
// @Override
// public void onCameraViewStarted(int width, int height) {
// Log.i(TAG, “onCameraViewStarted width=” + width + “, height=” + height);
// }
//
// @Override
// public void onCameraViewStopped() {
// Log.i(TAG, “onCameraViewStopped”);
// }
//
// @Override
// public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
// System.out.println(“…onCameraFrame…”);
// return inputFrame.rgba();
// }
// };

// private BaseLoaderCallback baseLoaderCallback = new BaseLoaderCallback(this) {
// @Override
// public void onManagerConnected(int status) {
// Log.i(TAG, “onManagerConnected status=” + status + “, javaCameraView=” + cameraView);
// switch (status) {
// case LoaderCallbackInterface.SUCCESS: {
// if (cameraView != null) {
// cameraView.setCvCameraViewListener(MainActivity.this);
// // 禁用帧率显示
// cameraView.disableFpsMeter();
// cameraView.enableView();
// }
// }
// break;
// default:
// super.onManagerConnected(status);
// break;
// }
// }
// };

//复写父类的 getCameraViewList 方法,把 javaCameraView 送到父 Activity,一旦权限被授予之后,javaCameraView 的 setCameraPermissionGranted 就会自动被调用。
@Override
protected List<? extends CameraBridgeViewBase> getCameraViewList() {
    Log.i(TAG, "getCameraViewList");
    List<CameraBridgeViewBase> list = new ArrayList<>();
    list.add(cameraView);
    return list;
}

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

    initLoadOpenCV();
    cameraView = (JavaCameraView) findViewById(R.id.camera_view);
    cameraView.setCvCameraViewListener(this);
    System.out.println(".........cameraView.setCvCameraViewListener..........");
    switchButton = (Button) findViewById(R.id.switchCamera);
    switchButton.setOnClickListener(this);

// if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)!= PackageManager.PERMISSION_DENIED) {
// ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},1);
// } else {
// cameraView.setCameraPermissionGranted();
// }
boolean havePermission = getPermissionCamera(this);
System.out.println(“…getPermissionCamera…”+havePermission);
initClassifier();
initEyeDetector();
leftEye_template = new Mat();
rightEye_template = new Mat();

    cameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_BACK);
    isFrontCamera=false;
    cameraView.enableView();
}

/**
 * 确认camera权限
 * @param activity
 * @return
 */
public static boolean getPermissionCamera(Activity activity) {
    int cameraPermissionCheck = ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA);
    int readPermissionCheck = ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE);
    int writePermissionCheck = ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    if (cameraPermissionCheck != PackageManager.PERMISSION_GRANTED
            || readPermissionCheck != PackageManager.PERMISSION_GRANTED
            || writePermissionCheck != PackageManager.PERMISSION_GRANTED) {
        String[] permissions = new String[]{Manifest.permission.CAMERA,Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE};
        ActivityCompat.requestPermissions(
                activity,
                permissions,
                0);
        return false;
    } else {
        return true;
    }
}
private void initWindowSettings() {
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}

private void initLoadOpenCV() {
    boolean success = OpenCVLoader.initDebug();
    if(success) {
        Toast.makeText(this, "Loading opencv ......", Toast.LENGTH_SHORT).show();
    } else {
        Toast.makeText(this, "Can't load opencv", Toast.LENGTH_SHORT).show();
    }
}

@Override
public void onCameraViewStarted(int width, int height) {
    System.out.println(".........onCameraViewStarted..........");
    Toast.makeText(this, "onCameraViewStarted ", Toast.LENGTH_SHORT).show();
    mRgba = new Mat();
}

@Override
public void onCameraViewStopped() {
    mRgba.release();
}

@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {

// System.out.println(“…onCameraFrame…”);
mRgba = inputFrame.rgba();

    if(isFrontCamera) {
        //Core.rotate(mRgba,mRgba,Core.ROTATE_180);
        Core.flip(mRgba,mRgba,1);//解决前置镜头上下颠倒
    }


    return myfacedetect1(mRgba);
}

//初始化人脸级联分类器
private void initClassifier() {
    try {
        InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface_improved);
        File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
        File cascadeFile = new File(cascadeDir, "lbpcascade_frontalface_improved.xml");
        FileOutputStream os = new FileOutputStream(cascadeFile);
        byte[] buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = is.read(buffer)) != -1) {
            os.write(buffer, 0, bytesRead);
        }
        is.close();
        os.close();
        classifier = new CascadeClassifier(cascadeFile.getAbsolutePath());
        cascadeFile.delete();
        cascadeDir.delete();
    }   catch (Exception e) {
        e.printStackTrace();
    }
}

private Mat myfacedetect(Mat srcmat) {
    Imgproc.cvtColor(srcmat,srcmat,Imgproc.COLOR_BGRA2GRAY);
    MatOfRect faces = new MatOfRect();
    classifier.detectMultiScale(srcmat,faces,1.1,1,0,new Size(30,30), new Size());
    List<Rect> faceList = faces.toList();

// srcmat.copyTo(dstmat3);
if(faceList.size()>0) {
// Toast.makeText(MainActivity.this, “Michael test”, Toast.LENGTH_SHORT).show();
for(Rect rect : faceList) {
Imgproc.rectangle(srcmat,rect.tl(),rect.br(),new Scalar(255,0,255),4,8,0);
}
}
return srcmat;
}

private Mat myfacedetect1(Mat mRgba) {
    float mRelativefaceSize = 0.2f;
    if (mAbsoluteFaceSize == 0) {
        int height = mRgba.rows();
        if (Math.round(height * mRelativefaceSize) > 0) {
            mAbsoluteFaceSize = Math.round(height*mRelativefaceSize);
        }
    }
    MatOfRect faces = new MatOfRect();
    if(classifier != null) {
        classifier.detectMultiScale(mRgba,faces,1.1,2,2,new Size(mAbsoluteFaceSize,mAbsoluteFaceSize), new Size());
    }
    Rect[] facesArray = faces.toArray();
    Scalar faceRectColor = new Scalar(0,255,0,255);
    for (int i = 0; i<facesArray.length;i++) {
        Imgproc.rectangle(mRgba,facesArray[i].tl(),facesArray[i].br(),faceRectColor,2);
        selectEyesArea(facesArray[i],mRgba);
    }
    return mRgba;
}

//选定眼睛区域
private void selectEyesArea(Rect faceROI, Mat frame) {
    int offy = (int) (faceROI.height * 0.15f);
    int offx = (int) (faceROI.width * 0.12f);
    int sh = (int) (faceROI.height * 0.35f);
    int sw = (int) (faceROI.width * 0.3f);
    int gap = (int) (faceROI.width * 0.25f);
    Point lp_eye = new Point(faceROI.tl().x+offx,faceROI.tl().y+offy);
    Point lp_end = new Point(lp_eye.x+sw,lp_eye.y+sh);
    Imgproc.rectangle(frame,lp_eye,lp_end,EYE_RECT_COLOR,2);

    int right_offx = (int) (faceROI.width * 0.08f);

    Point rp_eye = new Point(faceROI.x+faceROI.width/2+right_offx,faceROI.tl().y+offy);
    Point rp_end = new Point(rp_eye.x+sw,rp_eye.y+sh);
    Imgproc.rectangle(frame,rp_eye,rp_end,EYE_RECT_COLOR,2);

    //使用级联分类器检测眼睛
    MatOfRect eyes = new MatOfRect();

    Rect left_eye_roi = new Rect();
    left_eye_roi.x = (int) lp_eye.x;
    left_eye_roi.y = (int) lp_eye.y;
    left_eye_roi.width = (int) (lp_end.x - lp_eye.x);
    left_eye_roi.height = (int) (lp_end.y - lp_eye.y);

    Rect right_eye_roi = new Rect();
    right_eye_roi.x = (int) rp_eye.x;
    right_eye_roi.y = (int) rp_eye.y;
    right_eye_roi.width = (int) (rp_end.x - rp_eye.x);
    right_eye_roi.height = (int) (rp_end.y - rp_eye.y);

    //级联分类器
    Mat leftEye = frame.submat(left_eye_roi);
    Mat rightEye = frame.submat(right_eye_roi);

    classifierEye.detectMultiScale(mRgba.submat(left_eye_roi),eyes,1.15,2,0,new Size(30,30),new Size());
    Rect[] eyesArray = eyes.toArray();
    for(int i=0; i<eyesArray.length;i++){
        Log.i(TAG, "Found left Eyes... ");
        leftEye.submat(eyesArray[i]).copyTo(leftEye_template);
    }
    if(eyesArray.length==0){
        Rect left_roi = matchEyeTemplate(leftEye,true);
        if(left_roi != null) {
            Imgproc.rectangle(leftEye,left_roi.tl(),left_roi.br(),EYE_RECT_COLOR,2);
        }
    }
    eyes.release();
    eyes = new MatOfRect();
    classifierEye.detectMultiScale(mRgba.submat(right_eye_roi),eyes,1.15,2,0,new Size(30,30),new Size());
    eyesArray = eyes.toArray();
    for(int i=0; i<eyesArray.length;i++){
        Log.i(TAG, "Found right Eyes... ");
        rightEye.submat(eyesArray[i]).copyTo(rightEye_template);
    }
    if(eyesArray.length==0){
        Rect right_roi = matchEyeTemplate(rightEye,true);
        if(right_roi != null) {
            Imgproc.rectangle(rightEye,right_roi.tl(),right_roi.br(),EYE_RECT_COLOR,2);
        }
    }
}

private Rect matchEyeTemplate(Mat src, Boolean left){
    Mat tpl = left ? leftEye_template : rightEye_template;
    if(tpl.cols() ==0 || tpl.rows() == 0) {
        return null;
    }
    int height = src.rows() - tpl.rows()+1;
    int width = src.cols() - tpl.cols()+1;
    if(height<1 || width <1){
        return null;
    }
    Mat result = new Mat(height,width, CvType.CV_32FC1);

    //模板匹配
    int method = Imgproc.TM_CCOEFF_NORMED;
    Imgproc.matchTemplate(src, tpl, result,method);
    Core.MinMaxLocResult minMaxLocResult = Core.minMaxLoc(result);
    Point maxloc = minMaxLocResult.maxLoc;

    //ROI
    Rect rect = new Rect();
    rect.x = (int) (maxloc.x);
    rect.y = (int) (maxloc.y);
    rect.width = tpl.cols();
    rect.height = tpl.rows();

    result.release();
    return rect;
}

private void initEyeDetector() {
    try {
        InputStream is = getResources().openRawResource(R.raw.haarcascade_eye_tree_eyeglasses);
        File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
        File cascadeFile = new File(cascadeDir, "haarcascade_eye_tree_eyeglasses.xml");
        FileOutputStream os = new FileOutputStream(cascadeFile);
        byte[] buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = is.read(buffer)) != -1) {
            os.write(buffer, 0, bytesRead);
        }
        is.close();
        os.close();
        classifierEye = new CascadeClassifier(cascadeFile.getAbsolutePath());
        cascadeFile.delete();
        cascadeDir.delete();
    }   catch (Exception e) {
        e.printStackTrace();
    }
}

@Override
public void onClick(View view) {
    switch (view.getId()){

        case R.id.switchCamera:
            if(isFrontCamera) {
                cameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_BACK);
                isFrontCamera=false;
                System.out.println("isFrontCamera=false");
            } else {
                cameraView.setCameraIndex(CameraBridgeViewBase.CAMERA_ID_FRONT);
                isFrontCamera=true;
                System.out.println("isFrontCamera=true");
            }
    }
    if(cameraView != null) {
        cameraView.disableView();
    }
    cameraView.enableView();
    System.out.println("..........onClick enableView............");

// Toast.makeText(this, "…enableView… ", Toast.LENGTH_SHORT).show();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    if(cameraView != null) {
        cameraView.disableView();
    }
}

}

结果:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/495254.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何利用超融合提升制造业开发测试效率 [附用户案例]

进入数字时代&#xff0c;越来越多的制造业企业正在通过自主研发的方式加速应用创新。由于研发效率在很大程度上取决于支持开发测试的服务器、存储等 IT 基础设施的性能&#xff0c;企业需要简单、灵活、高性能的 IT 基础架构&#xff0c;来为研发团队提供资源共享与快速交付支…

Windows微信可以上网但是浏览器却用不了网络如何解决

1、清除DNS缓存。这个主要用于某些网站打不开的情形。 首先同时按WINDOWSR键&#xff0c;在弹出窗口输入CMD&#xff0c;然后回车。 在弹出的命令提示符中输入ipconfig /flushdns&#xff0c;然后回车。 2、重置winsock目录&#xff0c;在命令提示符中输入netsh winsock reset&…

go读request.Body内容踩坑记

go读request.Body内容踩坑记 踩坑代码如下&#xff0c;当时是想获取body传过来的json func demo(c *httpserver.Context) {type ReqData struct {Id int json:"id" validate:"required" schema:"id"Title string json:"…

【LeetCode】-66. 加一

1. 题目 66. 加一 给定一个由 整数 组成的 非空 数组所表示的非负整数&#xff0c;在该数的基础上加一。 最高位数字存放在数组的首位&#xff0c; 数组中每个元素只存储单个数字。 你可以假设除了整数 0 之外&#xff0c;这个整数不会以零开头。 2. 示例 输入&#xff1a;dig…

【Python】【进阶篇】23、Django模板变量精讲

目录 23、Django模板变量精讲1. 模板变量1) 变量的命名规范2&#xff09;模板的变量语法3) 模板传参语法格式 23、Django模板变量精讲 在上一节《Django 模板加载与响应》中我们详细讲述了 模板与视图函数如何进行配合使用&#xff0c;同时我们介绍了加载与响应模板的两种方式…

【c语言】字符串输出方式 | API仿真

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ …

数据库中的 Schema 变更实现

线上沙龙-技术流第 30 期营业啦 05月09日&#xff08;周二&#xff09;19:30 KaiwuDB - B站直播间 传统数据库操作 Schema 变更时&#xff0c;第一步便是锁表&#xff0c;需持续到 Schema 变更操作完成。这样的做法虽然实现简单&#xff0c;无需考虑事务并发带来的影响&#…

密码学:编码概述.

密码学&#xff1a;编码概述. 目录&#xff1a; 密码学&#xff1a;编码概述. 编码的概念&#xff1a; Base编码&#xff1a; &#xff08;1&#xff09;Base64 &#xff08;2&#xff09;Base32 和 Base16 &#xff08;3&#xff09;uuencode &#xff08;4&#xff0…

Linux怎么查看centos版本

Linux怎么查看centos版本 1、 lsb_release -a LSB是Linux Standard Base的缩写&#xff0c;lsb_release命令用来显示LSB和特定版本的相关信息。 lsb_release -a LSB Version: :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics…

Sublime3的打开方式添加到右键菜单

http://jingyan.baidu.com/article/cdddd41c68c32753ca00e157.html Sublime Text 安装完成之后没有右键打开方式&#xff0c;打开文件很不方便。为了快捷打开文件&#xff0c;可以在系统的右键上添加Sublime Text打开方式。如图所示 百度经验:jingyan.baidu.com 工具/原料 Sub…

第五章:平面解析几何

1.平面向量 1.向量的概念 1.有向线段:规定了起点和终点的线段叫做有向线段。例如以A为起点,B为终点的有向线段记作: 2.有向线段的要素:方向和长度。其中方向是从起点到终点,长度是线段AB的长度,记作:2.向量 1.定义:既有大小又有方向的量叫做向量。 2.表示法:向量可用…

vue+Nodejs+Koa搭建前后端系统(四)--安装MYSQL

前言 计算机系统为Windows 10 专业版MYSQL采用压缩版安装&#xff0c;版本为 v8.0.32 下载MYSQL数据库 MYSQL官网地址&#xff1a;https://www.mysql.com/ DOWNLOADS - MySQL Community Server 下载压缩版 ZIP Archive表示压缩版&#xff08;相当于绿色版&#xff09;&…

PointPillars Fast Encoders for Object Detection from Point Clouds 论文学习

论文地址&#xff1a;PointPillars: Fast Encoders for Object Detection from Point Clouds Github 地址&#xff1a;PointPillars: Fast Encoders for Object Detection from Point Clouds 1. 解决了什么问题&#xff1f; 点云目标检测是自动驾驶领域的一个重要方向。自动…

机智云全品类家电家居智能化解决方案亮相AWE,轻量化方案赋能产品快速升级

随着物联网、AI技术在家电家居行业应用愈发成熟&#xff0c;软硬一体的低成本轻量化解决方案越来越受到中小家电企业青睐。作为一线家电品牌首选的物联网平台&#xff0c;机智云Gizwits积累沉淀了10年家电AIoT研发和实施运维经验&#xff0c;携全品类家电家居智能化解决方案亮相…

怎么让chatGTP写论文-chatGTP写论文工具

chatGTP如何写论文 ChatGPT是一个使用深度学习技术训练的自然语言处理模型&#xff0c;可以用于生成自然语言文本&#xff0c;例如对话、摘要、文章等。作为一个人工智能技术&#xff0c;ChatGPT可以帮助你处理一些文字内容&#xff0c;但并不能代替人类的创造性思考和判断。以…

796. 子矩阵的和(C++和Python3)——2023.5.6打卡

文章目录 QuestionIdeasCode Question 输入一个 n 行 m 列的整数矩阵&#xff0c;再输入 q 个询问&#xff0c;每个询问包含四个整数 x1,y1,x2,y2 &#xff0c;表示一个子矩阵的左上角坐标和右下角坐标。 对于每个询问输出子矩阵中所有数的和。 输入格式 第一行包含三个整数…

业务连续性

业务连续性 业务连续性管理业务连续性的概念业务连续性计划建设过程组织管理业务影响分析&#xff08;BIA&#xff09;BIA-1确定业务优先级BIA-2风险分析BIA-3资产优先级划分 制定及批准实施制定及批准实施-风险降低制定及批准实施-风险转移制定及批准实施-风险规避与风险接受制…

SuperMap GIS基础产品移动GIS FAQ集锦(2)

SuperMap GIS基础产品移动GIS FAQ集锦&#xff08;2&#xff09; 【iMobile】AR加载场景不显示 【问题原因】 1.场景切的缓存纹理压缩格式不是移动端支持的&#xff1b; 2.场景原点位置太远&#xff0c;加载后显示效果很小不起眼看不清 【解决方法】 1.确认场景缓存纹理压缩格…

gdal2tiles切图

gdal2tiles切图 文章目录 gdal2tiles切图切图流程瓦片合并参考链接 切图流程 从原始数据获取所需的最高级别的瓦片,更低级的瓦片只需从这些最高级瓦片一层一层生成. 这样速度更快:因为最高级的瓦片只能利用gdal从原始tif中获取,其速度受tif尺寸影响很大,且从tif上取得级别越低,…

MySQL安装配置教程(保姆级,包含环境变量的配置)适合小白

文章目录 MySQL安装教程下载链接官网下载安装配置环境变量配置 MySQL安装教程 下载链接 点击下载链接 官网下载 官网下载 2.官网下载 3.官网下载 4.官网下载 5.官网下载 这里我们无需注册&#xff0c;只需要点下载就好 安装配置 1.安装配置   选择第一个 2.安装配置…