`

OpenCVforAndroid应用之银行卡号识别 ------ 搞定开发环境

阅读更多

前阵子的考试、旅游让我有很长一阵子没来博客看看,现在寒假了,是时候写点、看点新的东西了!

前面我主要围绕着基于OpenCV的机器学习算法在图像识别处理上的应用来展开学习的,当然这些个技术(如银行卡号识别)最终都是要运用到实际生活中的。我们就拿银行卡号识别来说,大家用的最多的微信实际上就有了这个功能。大家打开微信钱包,绑定银行卡的时候是否在输入框右侧看到一个照相机一样的按钮呢,那就是实现银行卡号识别功能的地方。现在我们也模仿微信,将opencv机器学习移植到android上。

这个app是我之前用很短的时间完成的,旨在

1.进一步了解android编程

2.了解opencv移植到android的过程,方便开发

3.了解C++移植到android的过程,方便开发

我要完成的这个简单的app主要功能是:

1.通过手机相册中已有的照片(银行卡片)识别银行卡号(暂定农行)

2.通过手机拍照得到银行卡图片识别银行卡号(暂定农行)

 

由于开发时间较短,实现比较简单,主要是想尽快将成果整合出来,我将用两三篇博客总结一下主要技术要点,接下来是第一部分:

                                                             

                                            一、搞定开发环境

 

             (1) OpenCVforAndroid

               环境搭建

               1> eclipse for android(推荐直接下载adt-bundle-windows)

                    Java作为现在android编程最主流的语言,eclipse是必不可少的编程环境,现在网上有很多自带adt插件的eclipse,当然你也可以下载adt插件,在eclipse下配置,这里推荐前者,省心省事方便无穷。

                   2>导入OpenCV Library

                   在OpenCV官网下载最新的OpenCVforAndroid,解压到workspace所在盘下;
                                                     

                   进入eclipse,导入OpenCV Library(在项目一栏中右击选择Import);
                                                         选择上图所选选项

                  选择……\OpenCV-android-sdk\sdk,就可将OpenCV导入到Eclipse中。
                                                      

                                                      导入成功!


                     测试程序

                 1>新建一个android application project

                      2> 导入OpenCV Library,右键项目,点击“Bulid Path”,选择configure build path,add我们导入的OpenCV Library。

                      3> 编程验证:点击按钮,灰度化图片            

 

	<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
	    xmlns:tools="http://schemas.android.com/tools"
	    android:layout_width="match_parent"
	    android:layout_height="match_parent"
	    android:paddingBottom="@dimen/activity_vertical_margin"
	    android:paddingLeft="@dimen/activity_horizontal_margin"
	    android:paddingRight="@dimen/activity_horizontal_margin"
	    android:paddingTop="@dimen/activity_vertical_margin"
	    tools:context="com.example.useopencvtest.MainActivity" >
	
	    <TextView
	        android:id="@+id/textView1"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:text="@string/hello_world" />
	
	    <ImageView
	        android:id="@+id/imageView2"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:layout_alignLeft="@+id/imageView1"
	        android:layout_alignParentBottom="true"
	        android:layout_marginBottom="159dp"
	        android:src="@drawable/abc_ab_solid_light_holo" />
	
	    <ImageView
	        android:id="@+id/imageView1"
	        android:layout_width="100dp"
	        android:layout_height="150dp"
	        android:layout_below="@+id/textView1"
	        android:layout_centerHorizontal="true"
	        android:layout_marginTop="27dp"
	        android:src="@drawable/bank" />
	
	    <Button
	        android:id="@+id/button1"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:layout_alignTop="@+id/imageView2"
	        android:layout_marginTop="43dp"
	        android:layout_toRightOf="@+id/imageView1"
	        android:text="Button" />
	
	</RelativeLayout>

 

 

 

 

package com.example.useopencvtest;
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.Mat;
import org.opencv.imgproc.Imgproc;

import android.content.pm.ApplicationInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

import com.example.useopencvtest.R.id;


public class MainActivity extends ActionBarActivity {
	ImageView image;
	Button btn;
	String TAG = "AAA";
	 //OpenCV库加载并初始化成功后的回调函数   
    private  BaseLoaderCallback mLoaderCallback =  new  BaseLoaderCallback( this ) {  
 
        @Override   
        public   void  onManagerConnected( int  status) {  
            // TODO Auto-generated method stub   
            switch  (status){  
            case  BaseLoaderCallback.SUCCESS:  
               Log.i(TAG,  "成功加载" );  
                break ;  
            default :  
                super .onManagerConnected(status);  
               Log.i(TAG,  "加载失败" );  
                break ;  
           }  
       }  
   };  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        image = (ImageView)findViewById(R.id.imageView2);
        btn = (Button)findViewById(id.button1);
        btn.setOnClickListener( new  ProcessClickListener());  
    }
    
    private   class  ProcessClickListener  implements  OnClickListener{  
        
        @Override   
        public   void  onClick(View v) {  
            // TODO Auto-generated method stub   
        	use();
       	}  
   }  

    public void use()
    {
        Bitmap bitmap = getRes("bank");
        Mat temp = new Mat();
        Mat mat = new Mat();
    	Utils.bitmapToMat(bitmap, temp);
    	Imgproc.cvtColor(temp, mat, Imgproc.COLOR_BGR2GRAY);
    	Utils.matToBitmap(mat, bitmap);
    	this.image.setImageBitmap(bitmap); 
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
    
    public Bitmap getRes(String name) {//获得res文件夹下的图片,得到bmp图片
   	 ApplicationInfo appInfo = getApplicationInfo();
   	 int resID = getResources().getIdentifier(name, "drawable", appInfo.packageName);
   	 return BitmapFactory.decodeResource(getResources(), resID);
   	 }
    
    @Override   
    protected   void  onResume() {  
        // TODO Auto-generated method stub   
        super .onResume();  
        //load OpenCV engine and init OpenCV library   
       OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_4, getApplicationContext(), mLoaderCallback);  
       Log.i(TAG,  "onResume sucess load OpenCV..." );  
//     new Handler().postDelayed(new Runnable(){   
//  
//         @Override   
//         public void run() {   
//             // TODO Auto-generated method stub   
//             procSrc2Gray();   
//         }   
//            
//     }, 1000);   
         
   }  
}

 结果:
                                                               
         参考:http://blog.csdn.net/yanzi1225627/article/details/16917961

              (2)Java的C++接口--------JNI

             环境搭建

             很多情况是开发者已经用C++进行了opencv的开发,想在移动端直接使用,这时候使用opencvforandroid就显得麻烦很多了,那这里我们可以使用Java中的JNI接口,直接调用C++的代码。

                 需要的工具:在(1)中的基础上,只需要安装NDK就可以了(r8版本以上)(注:现在你在百度上搜索的大部分还是写的NDK+Cygwin,但是实际上新版本的NDK(r8以上,我用的是r10版本)是不需要下载Cygwin,下过的朋友知道,这个玩意很坑的,我当初下了一个晚上都没下好)

                在下载安装好NDK后,参照             http://jingyan.baidu.com/article/5d6edee22d908799eadeec9f.html配置NDK。

 

               编程测试:

               MainActivity.java

              

package com.example.haveimgfun;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap.Config;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;


public class MainActivity extends ActionBarActivity {
	
	ImageView imgHuaishi;  
	Button btnNDK;
    
	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imgHuaishi = (ImageView)findViewById(R.id.img_huaishi);
        btnNDK = (Button)findViewById(R.id.btn_gray_process);
      //  btnNDK.setOnClickListener( new  MyClickListener());  
        btnNDK.setOnClickListener(new OnClickListener()
        {//按钮事件
           public void onClick(View v) {
              // TODO Auto-generated method stub
        	   System.out.println("进来了");
        	   Bitmap src = BitmapFactory.decodeResource(getResources(), R.drawable.img); 
        	   int h = src.getHeight();
        	   int w = src.getWidth();
        	   int temp[] = new int[h*w];
        	   int result[] = new int[h*w];
        	   src.getPixels(temp, 0, w, 0, 0, w, h);
        	   result = LibImgFun.ImgFun(temp, w, h);
        	   System.out.println("成功了");
        	   Bitmap last = Bitmap.createBitmap(w, h, Config.RGB_565);
        	   last.setPixels(result, 0, w, 0, 0, w, h);
        	   imgHuaishi.setImageBitmap(last); 
           }           
        });
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

           LibImgFun.java

package com.example.haveimgfun;

public class LibImgFun {  
static {   
        System.loadLibrary("ImgFun");   
       }   
      /** 
            * @param width the current view width 
            * @param height the current view height 
*/ 
    public static native int[] ImgFun(int[] buf, int w, int h);  
}

 

右击项目,点击android tools选择add native support,这样会出现一个jni文件夹,我们新建文件如下:
                                                       
Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)  
OPENCV_CAMERA_MODULES:=off
override OPENCV_INSTALL_MODULES:=on
 OPENCV_LIB_TYPE:=SHARED

OPENCV_LIB_TYPE :=STATIC
$(info ==$(OPENCV_INSTALL_MODULES)==)
include G:/OpenCV-2.4.9-android-sdk/sdk/native/jni/OpenCV.mk


LOCAL_MODULE    := ImgFun
LOCAL_SRC_FILES := ImgFun.cpp

include $(BUILD_SHARED_LIBRARY)

  Application.mk

APP_STL:=gnustl_static
APP_CPPFLAGS:=-frtti -fexceptions 
APP_ABI:=armeabi armeabi-v7a 
APP_PLATFORM := android-8

 ImgFun.cpp

#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <opencv2/opencv.hpp>
using namespace cv;
extern "C" {
JNIEXPORT jintArray JNICALL Java_com_example_haveimgfun_LibImgFun_ImgFun(
JNIEnv* env, jobject obj, jintArray buf, int w, int h);
JNIEXPORT jintArray JNICALL Java_com_example_haveimgfun_LibImgFun_ImgFun(
JNIEnv* env, jobject obj, jintArray buf, int w, int h){
	jint *cbuf;
	cbuf = env->GetIntArrayElements(buf, NULL);
	if(cbuf == NULL)
	{
		return 0;
	}
	Mat myimg(h, w, CV_8UC4, (unsigned char*)cbuf);
	for(int j=0; j<myimg.rows/2; j++)
	{
		myimg.row(j).setTo(Scalar(0, 0, 0, 0));
	}
	int size=w*h;
	jintArray result = env->NewIntArray(size);
	env->SetIntArrayRegion(result, 0, size, cbuf);
	env->ReleaseIntArrayElements(buf, cbuf, 0);
	return result;
	}

}

 至此,环境搭建及测试完毕!

  • 大小: 91.3 KB
  • 大小: 27.4 KB
  • 大小: 37.6 KB
  • 大小: 6.7 KB
  • 大小: 176.4 KB
  • 大小: 2.9 KB
分享到:
评论
1 楼 cyw 2016-01-23  
写的很棒。加油

相关推荐

    lane-detection.rar_Java车道_java 车道识别_lane-detection_多车道_车道线

    主要是在opencvforandroid的基础上实现了简单的车道线识别,同时增加了语音提示,还有简单的车型识别。效果还行,用多线程实现的。

    TRsign:使用HOG + SVM(dlib 19.19 + opencv 4.3.0)检测TRsign

    自述文件 Aplicativocompatívelcom: Android SDK API-29 NDK 21.0.6113669 OpencvForAndroid 4.3.0 Dlib 19.19 执照

    Android+Opencv(人脸检测 lbpcascade_frontalface)

    opencv基于android平台的人脸检测,分析OpencvforAndroid官网demo,用的是lbpcascade_frontalface模型文件,后面会添加mtcnn检测的代码,大家一起交流

    #这是一篇关于 LabVIEW 介绍说明、使用技巧和优缺点对文章

    labview

    重庆大学数字电子技术试题.pdf

    重庆大学期末考试试卷,重大期末考试试题,试题及答案

    重庆大学2012电磁场考题(A)参考答案及评分标准.pdf

    重庆大学期末考试试卷,重大期末考试试题,试题及答案

    5G智慧港口解决方案.pptx

    在现有省、市港口信息化系统进行有效整合基础上,借鉴新 一代的感知-传输-应用技术体系,实现对码头、船舶、货物、重 大危险源、危险货物装卸过程、航管航运等管理要素的全面感知、 有效传输和按需定制服务,为行政管理人员和相关单位及人员提 供高效的管理辅助,并为公众提供便捷、实时的水运信息服务。 建立信息整合、交换和共享机制,建立健全信息化管理支撑 体系,以及相关标准规范和安全保障体系;按照“绿色循环低碳” 交通的要求,搭建高效、弹性、高可扩展性的基于虚拟技术的信 息基础设施,支撑信息平台低成本运行,实现电子政务建设和服务模式的转变。 实现以感知港口、感知船舶、感知货物为手段,以港航智能 分析、科学决策、高效服务为目的和核心理念,构建“智慧港口”的发展体系。 结合“智慧港口”相关业务工作特点及信息化现状的实际情况,本项目具体建设目标为: 一张图(即GIS 地理信息服务平台) 在建设岸线、港口、港区、码头、泊位等港口主要基础资源图层上,建设GIS 地理信息服务平台,在此基础上依次接入和叠加规划建设、经营、安全、航管等相关业务应用专题数据,并叠 加动态数据,如 AIS/GPS/移动平台数据,逐步建成航运管理处 "一张图"。系统支持扩展框架,方便未来更多应用资源的逐步整合。 现场执法监管系统 基于港口(航管)执法基地建设规划,依托统一的执法区域 管理和数字化监控平台,通过加强对辖区内的监控,结合移动平 台,形成完整的多维路径和信息追踪,真正做到问题能发现、事态能控制、突发问题能解决。 运行监测和辅助决策系统 对区域港口与航运业务日常所需填报及监测的数据经过科 学归纳及分析,采用统一平台,消除重复的填报数据,进行企业 输入和自动录入,并进行系统智能判断,避免填入错误的数据, 输入的数据经过智能组合,自动生成各业务部门所需的数据报 表,包括字段、格式,都可以根据需要进行定制,同时满足扩展 性需要,当有新的业务监测数据表需要产生时,系统将分析新的 需求,将所需字段融合进入日常监测和决策辅助平台的统一平台中,并生成新的所需业务数据监测及决策表。 综合指挥调度系统 建设以港航应急指挥中心为枢纽,以各级管理部门和经营港 口企业为节点,快速调度、信息共享的通信网络,满足应急处置中所需要的信息采集、指挥调度和过程监控等通信保障任务。 设计思路 根据项目的建设目标和“智慧港口”信息化平台的总体框架、 设计思路、建设内容及保障措施,围绕业务协同、信息共享,充 分考虑各航运(港政)管理处内部管理的需求,平台采用“全面 整合、重点补充、突出共享、逐步完善”策略,加强重点区域或 运输通道交通基础设施、运载装备、运行环境的监测监控,完善 运行协调、应急处置通信手段,促进跨区域、跨部门信息共享和业务协同。 以“统筹协调、综合监管”为目标,以提供综合、动态、实 时、准确、实用的安全畅通和应急数据共享为核心,围绕“保畅通、抓安全、促应急"等实际需求来建设智慧港口信息化平台。 系统充分整合和利用航运管理处现有相关信息资源,以地理 信息技术、网络视频技术、互联网技术、移动通信技术、云计算 技术为支撑,结合航运管理处专网与行业数据交换平台,构建航 运管理处与各部门之间智慧、畅通、安全、高效、绿色低碳的智 慧港口信息化平台。 系统充分考虑航运管理处安全法规及安全职责今后的变化 与发展趋势,应用目前主流的、成熟的应用技术,内联外引,优势互补,使系统建设具备良好的开放性、扩展性、可维护性。

    机械工程学位 Matlab.zip

    1.版本:matlab2014/2019a/2021a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    Matlab菌丝检测识别项目.zip

    提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

    基于django-xadmin的idc资产管理应用.zip

    基于django-xadmin的idc资产管理应用.zip

    电商数据分析.py

    电商数据分析.py

    头哥机组练习-第4关:16位快速加法器设计(计算机组成原理-谭志虎-华科大)

    头哥机组练习-第4关:16位快速加法器设计(计算机组成原理-谭志虎-华科大)

    Python实现春节烟花模拟介绍及代码示例.docx

    春节,作为中国最重要的传统节日之一,象征着团圆、喜庆和新的开始。烟花作为春节庆祝活动的重要元素,以其绚烂多彩、瞬间绽放的特点,给人们带来了无尽的欢乐和惊喜。然而,由于环境保护和安全的考虑,现实中烟花的燃放受到了诸多限制。因此,利用编程技术,模拟出春节烟花的效果,成为了一种新颖而有趣的方式。 本文将介绍一种基于Python编程语言的春节烟花模拟代码。通过简单的代码实现,我们可以创建出各种形态、颜色和动态效果的烟花,让人们在计算机屏幕上欣赏到一场别样的“烟花盛宴”。 一、代码介绍 该代码主要使用了Python的图形库pygame,以及random库来生成随机颜色和位置。pygame库是一个用于编写视频游戏的Python模块集,它可以创建窗口、绘制图形、处理键盘和鼠标事件等。random库则用于生成随机数,以模拟烟花的随机性和不确定性。 在代码中,我们定义了一个烟花类(Firework),包含烟花的初始位置、颜色、速度等属性,以及一个方法(update)用于更新烟花的位置和状态。然后,在主程序中,我们创建了一定数量的烟花对象,并在每一帧中更新它们的状态,同时在屏幕上绘制出来。 通过调整烟花类

    财务数据分析看版.xlsx

    Excel数据看板,Excel办公模板,Excel模板下载,Excel数据统计,数据展示

    social ski driver algorithm社会滑雪优化算法附matlab代码.zip

    1.版本:matlab2014/2019a/2021a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    辐射状系统配电网中的潮流解matlab代码.zip

    1.版本:matlab2014/2019a/2021a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    LabVIEW的概要分析与介绍

    LabVIEW(Laboratory Virtual Instrument Engineering Workbench)是一款由美国国家仪器公司(National Instruments)开发的图形化编程语言和开发环境,广泛应用于数据采集、控制系统、测试测量、科学研究等领域。以下是关于 LabVIEW 的资源描述: 开发环境和工具:LabVIEW 提供了一个直观易用的开发环境,允许用户通过拖放式的方式创建虚拟仪器(Virtual Instruments,简称VIs)并连接它们,构建复杂的控制和测量系统。LabVIEW 还提供了丰富的图形化编程工具和函数库,包括数据处理、信号分析、仪器控制等功能,极大地简化了开发过程。 图形化编程语言:LabVIEW 使用图形化编程语言 G(Graphical Programming Language)进行编程,采用了数据流编程模型,使得程序的逻辑结构更直观清晰。用户可以通过连接各种图形化的函数块(Node)来实现数据处理、控制逻辑等功能,无需编写复杂的代码,降低了学习和开发的门槛。 应用领域:LabVIEW 在科学研究、工程控制、教育培训等领域有着

    单片机实验或课设-定时器控制交通指示灯

    定时器控制交通指示灯 用C语言编写,也可以改成汇编

    城区智慧城市感知建设项目-设计方案(306页WORD).docx

    共建共享共治智慧城市感知系统,实现视频资源的集约化;视频感知,AI加持,构建视频AI资源池;融合感知数据与业务数据;实现城市状态的实时监测、城市异常的智能预警以及对事件的主动学习、预警和决策模型的自动训练,以数据和知识驱动实现城市日常治理、公共服务、应急处置和发展筹划等业务的可视化、智能化、可量化评估与持续优化,推动城市治理体系和治理能力现代化;从而有效支撑综合类业务及探索运营类业务。 在现有建设的基础上,补全前端多维信息感知设备包括路口交通感知、规范交通标示、人脸抓拍、信号控制等系统,为政府综合业务、承载城市运行管理、应急指挥、民生服务等业务,重点在运行监测、协同指挥、仿真决策、开放服务等方面,通过全面感知城市运行状态,实现城市日常运行管理以及突发事件应急联动指挥等全景指挥中心功能。

    阿里巴巴笔试题目.docx

    校园招聘笔试题目及答案

Global site tag (gtag.js) - Google Analytics