美文网首页
2021.8 第九届全国大学生光电竞赛

2021.8 第九届全国大学生光电竞赛

作者: AdRainty | 来源:发表于2021-08-24 10:39 被阅读0次

    一、竞赛要求

    图片.png
    图片.png

    二、赛题分析

    已经改成线上赛了,不需要测定标准值了

    按照要求设计部分需要全程在手机上实现,光源普通光不超过20W,激光不超过10W,经过测试透射光很小几乎不存在,因此考虑用到漫反射手机摄像头获取光照强度,为了避免外界光的影响,还需要设计暗室环境

    三、手机app界面设计

    app流程如下


    图片.png

    3.1 首页面设计

    由于要求手机界面产生学校和队伍名称,考虑采用开头动画的方式,设计一个可以进行跳过的动画来展示队伍信息

    package com.example.appsrc;
    
    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.view.View;
    import android.view.WindowManager;
    import android.widget.Button;
    import android.widget.TextView;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class Welcome extends AppCompatActivity implements View.OnClickListener {
    
        private int recLen = 15;//跳过倒计时提示15秒
        private TextView tv;
        Timer timer = new Timer();  //定义一个计时器
        private Handler handler;
        private Runnable runnable;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            getSupportActionBar().hide();
            //定义全屏参数
            int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
            //设置当前窗体为全屏显示
            getWindow().setFlags(flag, flag);
            setContentView(R.layout.fragment_main);
            initView();
            timer.schedule(task, 1000, 1000);//等待时间一秒,停顿时间一秒
            /**
             * 正常情况下不点击跳过
             */
            handler = new Handler();
            handler.postDelayed(runnable = new Runnable() {
                @Override
                public void run() {
                    //从闪屏界面跳转到首界面
                    Intent intent = new Intent(Welcome.this, Category.class);
                    startActivity(intent);
                    finish();
                }
            }, 15000);//延迟15S后发送handler信息
    
        }
    
        private void initView() {
            tv = findViewById(R.id.skip);//跳过
            tv.setOnClickListener(this);//跳过监听
        }
    
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                runOnUiThread(new Runnable() { // UI thread
                    @Override
                    public void run() {
                        recLen--;
                        tv.setText("跳过 " + recLen);
                        if (recLen < 0) {
                            timer.cancel();
                            tv.setVisibility(View.GONE);//倒计时到0隐藏字体
                        }
                    }
                });
            }
        };
    
        /**
         * 点击跳过
         */
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.skip:
                    //从闪屏界面跳转到首界面
                    Intent intent = new Intent(Welcome.this, Category.class);
                    startActivity(intent);
                    finish();
                    if (runnable != null) {
                        handler.removeCallbacks(runnable);
                    }
                    break;
                default:
                    break;
            }
        }
    }
    

    xml代码如下

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@color/lightSteelBlue"
        xmlns:custom="http://schemas.android.com/apk/res-auto">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="40sp"
            android:textColor="@color/dimGray"
            android:text="@string/welcome"
            android:gravity="center"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="150sp"
            />
    
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/la"
            android:layout_gravity="right"
            android:layout_marginTop="40dp"
            />
    
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/la3"
            android:layout_marginTop="280dp"
            />
    
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/la2"
            android:layout_gravity="center_horizontal|bottom"
            android:layout_marginBottom="120dp"
            android:layout_marginLeft="155dp"
            />
    
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/logo"/>
    
        <Button
            android:id="@+id/skip"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|right"
            android:background="@drawable/botton_style"
            android:layout_marginBottom="20dp"
            android:layout_marginRight="20dp"
            android:padding="20dp"
            android:text="@string/skip"
            android:textSize="17sp" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#66666666"
            android:text="@string/team"
            android:gravity="center"
            android:layout_gravity="center"
            android:padding="20dp"
            android:textColor="@android:color/white"
            android:textSize="18sp" />
    
    
    </FrameLayout>
    

    3.2 选择苹果

    由于要求测定不同种类的苹果,因此增加一个界面,选择两种不同的苹果,传输不同的Buddle,分别对应两种不同的函数。
    代码如下:

    package com.example.appsrc;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    
    public class Category extends Activity {
        private Button chooseRed, chooseYel;
    
        @Override
        protected void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            setContentView(R.layout.catelog_ele);
            chooseRed = (Button) findViewById(R.id.chooseRed);
            chooseYel = (Button) findViewById(R.id.chooseYellow);
            setListeners();
    
        }
    
        private void setListeners(){
            chooseRed.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(Category.this, MainActivity.class);
                    String s = "Red";
                    intent.putExtra("data",s);
                    startActivity(intent);
                }
            });
            chooseYel.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(Category.this, MainActivity.class);
                    String s = "Yellow";
                    intent.putExtra("data",s);
                    startActivity(intent);
                }
            });
        }
    }
    

    3.3 拍照并读取数据

    拍照算法比较常见,获取图片的亮度值采用Camara相机回调自带的NV21数组


    图片.png

    其中Y代表的是每个像素点的亮度值,亮度值转化公式如下


    图片.png

    其中我们获取的图片经过裁剪成一个圆形,代码如下

    package com.example.appsrc;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.drawable.BitmapDrawable;
    import android.graphics.drawable.Drawable;
    import android.util.AttributeSet;
    import android.content.res.TypedArray;
    import android.graphics.PorterDuff;
    import android.graphics.PorterDuffXfermode;
    import android.graphics.Rect;
    import android.graphics.drawable.NinePatchDrawable;
    import android.util.Log;
    import android.widget.ImageView;
    
    public class RoundImageView extends androidx.appcompat.widget.AppCompatImageView {
    
        private static final String TAG = "RoundImageView";
        private static final boolean DEBUG = true;
        private int mBorderThickness = 0;
        private Context mContext;
        private int defaultColor = 0xFFFFFFFF;
        // 如果只有其中一个有值,则只画一个圆形边框
        private int mBorderOutsideColor = 0;
        private int mBorderInsideColor = 0;
        // 控件默认长、宽
        private int defaultWidth = 0;
        private int defaultHeight = 0;
        //控件画圆的宽高。
        private int requestWH = 0;
    
        public RoundImageView(Context context) {
            this(context, null);
        }
    
        public RoundImageView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public RoundImageView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            mContext = context;
            setCustomAttributes(attrs);
        }
    
        /**
         * 获得自定义控件属性值
         *
         * @param attrs
         */
        private void setCustomAttributes(AttributeSet attrs) {
            TypedArray a = mContext.obtainStyledAttributes(attrs,
                    R.styleable.RoundImageView);
            mBorderThickness = a.getDimensionPixelSize(
                    R.styleable.RoundImageView_border_thickness, 0);
            mBorderOutsideColor = a
                    .getColor(R.styleable.RoundImageView_border_outside_color,
                            defaultColor);
            mBorderInsideColor = a.getColor(
                    R.styleable.RoundImageView_border_inside_color, defaultColor);
            a.recycle();
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            Drawable drawable = getDrawable();
            if (drawable == null) {
                return;
            }
    
            if (getWidth() == 0 || getHeight() == 0) {
                return;
            }
            this.measure(0, 0);
            if (drawable.getClass() == NinePatchDrawable.class) {
                return;
            }
            Bitmap b = ((BitmapDrawable) drawable).getBitmap();
            Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);
    
            int radius = getRadius(canvas);
    
            Bitmap roundBitmap = getCroppedRoundBitmap(bitmap, radius);
            canvas.drawBitmap(roundBitmap, requestWH / 2 - radius, requestWH
                    / 2 - radius, null);
        }
    
        /**
         * 获取画园的半径,并且绘制圆的外边框
         *
         * @param canvas
         * @return
         */
        private int getRadius(Canvas canvas) {
            if (defaultWidth == 0) {
                defaultWidth = getWidth();
    
            }
            if (defaultHeight == 0) {
                defaultHeight = getHeight();
            }
            requestWH = defaultHeight > defaultWidth ? defaultWidth : defaultHeight;
    
            int radius = 0;
            if (mBorderInsideColor != defaultColor
                    && mBorderOutsideColor != defaultColor) {// 定义画两个边框,分别为外圆边框和内圆边框
                radius = requestWH / 2 - 2 * mBorderThickness;
                // 画内圆
                drawCircleBorder(canvas, radius + mBorderThickness / 2,
                        mBorderInsideColor);
                // 画外圆
                drawCircleBorder(canvas, radius + mBorderThickness
                        + mBorderThickness / 2, mBorderOutsideColor);
            } else if (mBorderInsideColor != defaultColor
                    && mBorderOutsideColor == defaultColor) {// 定义画一个边框
                radius = requestWH / 2 - mBorderThickness;
                drawCircleBorder(canvas, radius + mBorderThickness / 2,
                        mBorderInsideColor);
            } else if (mBorderInsideColor == defaultColor
                    && mBorderOutsideColor != defaultColor) {// 定义画一个边框
                radius = (defaultWidth < defaultHeight ? defaultWidth
                        : defaultHeight) / 2 - mBorderThickness;
                drawCircleBorder(canvas, radius + mBorderThickness / 2,
                        mBorderOutsideColor);
            } else {// 没有边框
                radius = requestWH / 2;
            }
            return radius;
        }
    
        /**
         * 获取裁剪后的圆形图片
         *
         * @param radius 半径
         */
        private static Bitmap getCroppedRoundBitmap(Bitmap bmp, int radius) {
            Bitmap scaledSrcBmp;
            int diameter = radius * 2;
    
            // 为了防止宽高不相等,造成圆形图片变形,因此截取长方形中处于中间位置最大的正方形图片
            int bmpWidth = bmp.getWidth();
            int bmpHeight = bmp.getHeight();
            int squareWidth = 0, squareHeight = 0;
            int x = 0, y = 0;
            Bitmap squareBitmap;
            if (DEBUG) {
                Log.d(TAG, "the Bitmap w:" + bmpWidth + " the Bitmap h:" + bmpHeight);
            }
    
            if (bmpHeight > bmpWidth) {// 高大于宽
                squareWidth = squareHeight = bmpWidth;
                x = 0;
                y = (bmpHeight - bmpWidth) / 2;
                // 截取正方形图片
                squareBitmap = Bitmap.createBitmap(bmp, x, y, squareWidth,
                        squareHeight);
            } else if (bmpHeight < bmpWidth) {// 宽大于高
                squareWidth = squareHeight = bmpHeight;
                x = (bmpWidth - bmpHeight) / 2;
                y = 0;
                squareBitmap = Bitmap.createBitmap(bmp, x, y, squareWidth,
                        squareHeight);
            } else {
                squareBitmap = bmp;
            }
    
            if (squareBitmap.getWidth() != diameter
                    || squareBitmap.getHeight() != diameter) {
                scaledSrcBmp = Bitmap.createScaledBitmap(squareBitmap, diameter,
                        diameter, true);
    
            } else {
                scaledSrcBmp = squareBitmap;
            }
            Bitmap output = Bitmap.createBitmap(scaledSrcBmp.getWidth(),
                    scaledSrcBmp.getHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(output);
    
            Paint paint = new Paint();
            Rect rect = new Rect(0, 0, scaledSrcBmp.getWidth(),
                    scaledSrcBmp.getHeight());
    
            paint.setAntiAlias(true);
            paint.setFilterBitmap(true);
            paint.setDither(true);
            canvas.drawARGB(0, 0, 0, 0);
            canvas.drawCircle(scaledSrcBmp.getWidth() / 2,
                    scaledSrcBmp.getHeight() / 2, scaledSrcBmp.getWidth() / 2,
                    paint);
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            canvas.drawBitmap(scaledSrcBmp, rect, rect, paint);
            bmp.recycle();
            squareBitmap.recycle();
            scaledSrcBmp.recycle();
            bmp = null;
            squareBitmap = null;
            scaledSrcBmp = null;
            return output;
        }
    
        /**
         * 边缘画圆
         */
        private void drawCircleBorder(Canvas canvas, int radius, int color) {
            Paint paint = new Paint();
            /* 去锯齿 */
            paint.setAntiAlias(true);
            paint.setFilterBitmap(true);
            paint.setDither(true);
            paint.setColor(color);
            /* 设置paint的 style 为STROKE:空心 */
            paint.setStyle(Paint.Style.STROKE);
            /* 设置paint的外框宽度 */
            paint.setStrokeWidth(mBorderThickness);
            canvas.drawCircle(requestWH / 2, requestWH / 2, radius, paint);
        }
    
        /**
         * 设置外边框的宽度
         *
         * @param borderWith
         */
        public void setBorderWith(int borderWith) {
            mBorderThickness = borderWith;
        }
    
        /**
         * 设置外边框的颜色
         *
         * @param outsideColor
         */
        public void setBorderOutsideColor(int outsideColor) {
            mBorderOutsideColor = outsideColor;
        }
    
        /**
         * 设置内边框的颜色
         *
         * @param insideColor
         */
        public void setBorderInsideColor(int insideColor) {
            mBorderInsideColor = insideColor;
        }
    
    }
    

    手机1:1拍照出来的像素为3472*3472,着实够大,我们亮度点不需要取那么多,最后决定取500个最亮的像素点取平均值算出总亮度,因此核心代码如下

    package com.example.appsrc;
    
    import android.Manifest;
    import android.content.ContentValues;
    import android.content.Context;
    import android.content.Intent;
    import android.content.pm.PackageManager;
    import android.graphics.Bitmap;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.PorterDuff;
    import android.graphics.PorterDuffXfermode;
    import android.graphics.Rect;
    import android.graphics.RectF;
    import android.hardware.Camera;
    import android.net.Uri;
    import android.os.Build;
    import android.os.Bundle;
    
    import androidx.core.app.ActivityCompat;
    import androidx.core.content.ContextCompat;
    import androidx.core.content.FileProvider;
    import androidx.core.os.EnvironmentCompat;
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.os.Environment;
    import android.provider.MediaStore;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ImageView;
    import android.widget.TextView;
    import android.widget.Toast;
    import com.tbruyelle.rxpermissions2.RxPermissions;
    
    import java.io.File;
    import java.io.IOException;
    import java.lang.reflect.Array;
    import java.text.DecimalFormat;
    import java.text.SimpleDateFormat;
    import java.util.Arrays;
    import java.util.Date;
    import java.util.List;
    import java.util.Locale;
    
    import static java.lang.Math.pow;
    
    public class MainActivity extends AppCompatActivity {
    
        private static final String TAG = "ShortcutUtils";
    
        // 拍照的requestCode
        private static final int CAMERA_REQUEST_CODE = 0x00000010;
        // 申请相机权限的requestCode
        private static final int PERMISSION_CAMERA_REQUEST_CODE = 0x00000012;
        private String category;
        /**
         * 用于保存拍照图片的uri
         */
        private Uri mCameraUri;
        TextView sugarView;
        private static final int CROP_PHOTO = 12;
    
        /**
         * 用于保存图片的文件路径,Android 10以下使用图片路径访问图片
         */
        private String mCameraImagePath;
    
        /**
         *  是否是Android 10以上手机
         */
        private final boolean isAndroidQ = Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q;
    
        //预览控件
        private Button takePicBtn, clearPicBtn;
        private ImageView imgView;
        private float light = 0;
    
        private void getPermissions() {
            RxPermissions rxPermissions = new RxPermissions(this);
            rxPermissions.request(Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    .subscribe(granted -> {
                        if (granted) {
                            Toast.makeText(getApplicationContext(), "已经获取所需权限", Toast.LENGTH_SHORT).show();
                        } else {
                            Toast.makeText(getApplicationContext(), "未能获取所需权限", Toast.LENGTH_SHORT).show();
                        }
                    });
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Intent intent=getIntent();
            category = intent.getStringExtra("data");
            setContentView(R.layout.activity_main);
            getPermissions();
            getSupportActionBar().hide();
            takePicBtn = (Button) findViewById(R.id.takePicture);
            clearPicBtn = (Button) findViewById(R.id.clearImage);
            imgView = (ImageView) findViewById(R.id.myCustom);
            sugarView = (TextView) findViewById(R.id.SugarText);
    
            imgView.setImageResource(R.drawable.picture);
    
            setListeners();
        }
    
        private void setListeners(){
            takePicBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    checkPermissionAndCamera();
                }
            });
            clearPicBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    clearDegree();
                }
            });
        }
    
        private void clearDegree(){
            light = 0;
            imgView.setImageResource(R.drawable.picture);
            sugarView.setText(R.string.currentSugar);
        }
    
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            try {
                processOnActivityResult(this, requestCode, resultCode, data);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public void processOnActivityResult(Context context,int requestCode, int resultCode, Intent data) throws IOException {
            switch (requestCode) {
                case CAMERA_REQUEST_CODE:
                    if (resultCode == RESULT_OK) {
                        // Android 10 使用图片uri加载
                        Intent intent = new Intent("com.android.camera.action.CROP");
                        intent.setDataAndType(mCameraUri, "image/*");
                        // aspectX aspectY 是宽高的比例
                        intent.putExtra("aspectX", 1);
                        intent.putExtra("aspectY", 1);
                        // 设置裁剪图片的宽高
                        intent.putExtra("outputX", 150);
                        intent.putExtra("outputY", 150);
                        intent.putExtra("scale", true);
                        intent.putExtra("circleCrop", true);
                        // 裁剪后返回数据
                        // intent.putExtra("return-data", true);
                        File photoFile = null;
                        Uri photoUri = null;
                        if (isAndroidQ) {
                            // 适配android 10
                            photoUri = createImageUri();
                        } else {
                            try {
                                photoFile = createImageFile();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
    
                            if (photoFile != null) {
                                mCameraImagePath = photoFile.getAbsolutePath();
                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                                    //适配Android 7.0文件权限,通过FileProvider创建一个content类型的Uri
                                    photoUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", photoFile);
                                } else {
                                    photoUri = Uri.fromFile(photoFile);
                                }
                            }
                        }
    
                        mCameraUri = photoUri;
                        intent.putExtra(MediaStore.EXTRA_OUTPUT, mCameraUri);
                        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
                        // 启动intent。开始裁剪
                        // startActivityForResult(intent, CROP_PHOTO);
                        startActivityForResult(intent, CROP_PHOTO);
                    } else {
                        Toast.makeText(this,"取消",Toast.LENGTH_LONG).show();
                    }
                    break;
                case CROP_PHOTO:
                    try {
                        Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), mCameraUri);
                        imgView.setImageBitmap(bitmap);
                        light = getBright(bitmap);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    // 裁剪后返回数据
                    // intent.putExtra("return-data", true);
                    break;
            }
        }
    
        /**
         * 检查权限并拍照。
         * 调用相机前先检查权限。
         */
        private void checkPermissionAndCamera() {
            int hasCameraPermission = ContextCompat.checkSelfPermission(getApplication(),
                    Manifest.permission.CAMERA);
            if (hasCameraPermission == PackageManager.PERMISSION_GRANTED) {
                //有权限,调起相机拍照。
                openCamera();
            } else {
                //没有权限,申请权限。
                ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA},
                        PERMISSION_CAMERA_REQUEST_CODE);
            }
        }
    
        /**
         * 处理权限申请的回调。
         */
        @Override
        public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
            if (requestCode == PERMISSION_CAMERA_REQUEST_CODE) {
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    //允许权限,有调起相机拍照。
                    openCamera();
                } else {
                    //拒绝权限,弹出提示框。
                    Toast.makeText(this,"拍照权限被拒绝",Toast.LENGTH_LONG).show();
                }
            }
        }
    
        /**
         * 调起相机拍照
         */
        private void openCamera() {
            Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            // 判断是否有相机
            if (captureIntent.resolveActivity(getPackageManager()) != null) {
                File photoFile = null;
                Uri photoUri = null;
    
                if (isAndroidQ) {
                    // 适配android 10
                    photoUri = createImageUri();
                } else {
                    try {
                        photoFile = createImageFile();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
    
                    if (photoFile != null) {
                        mCameraImagePath = photoFile.getAbsolutePath();
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                            //适配Android 7.0文件权限,通过FileProvider创建一个content类型的Uri
                            photoUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", photoFile);
                        } else {
                            photoUri = Uri.fromFile(photoFile);
                        }
                    }
                }
    
                mCameraUri = photoUri;
                if (photoUri != null) {
                    captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
                    captureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                    startActivityForResult(captureIntent, CAMERA_REQUEST_CODE);
                }
            }
        }
    
        /**
         * 创建图片地址uri,用于保存拍照后的照片 Android 10以后使用这种方法
         *
         * @return 图片的uri
         */
        private Uri createImageUri() {
            String status = Environment.getExternalStorageState();
            // 判断是否有SD卡,优先使用SD卡存储,当没有SD卡时使用手机存储
            if (status.equals(Environment.MEDIA_MOUNTED)) {
                return getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new ContentValues());
            } else {
                return getContentResolver().insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, new ContentValues());
            }
        }
    
        /**
         * 创建保存图片的文件
         */
        private File createImageFile() throws IOException {
            String imageName = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
            File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
            if (!storageDir.exists()) {
                storageDir.mkdir();
            }
            File tempFile = new File(storageDir, imageName);
            if (!Environment.MEDIA_MOUNTED.equals(EnvironmentCompat.getStorageState(tempFile))) {
                return null;
            }
            return tempFile;
        }
    
        // 获取图片的亮度值
        public float getBright(Bitmap bm) {
            if(bm == null) return -1;
            int width = bm.getWidth();
            int height = bm.getHeight();
            float r, g, b;
            int count = 0;
            float bright = 0;
            float data[] = new float[500];
            for (int i = 0; i < width; i++) {
                for (int j = 0; j < height; j++) {
                    int localTemp = bm.getPixel(i, j);
                    if (localTemp == 0){
                        continue;
                    }
                    count++;
                    r = (localTemp | 0xff00ffff) >> 16 & 0x00ff;
                    g = (localTemp | 0xffff00ff) >> 8 & 0x0000ff;
                    b = (localTemp | 0xffffff00) & 0x0000ff;
                    bright = (float) (0.299 * r + 0.587 * g + 0.114 * b);
                    Arrays.sort(data);
                    if (count > 500) {
                        if (data[0] <= bright) {
                            data[0] = bright;
                        }
                    }
                    else {
                        data[count-1] = bright;
                    }
                }
            }
            light = totalCount(data);
            float sugar = (float) (-0.2039*light+19.33987);
            if (category.equals("Yellow")){
                sugar = (float) (sugar - 2.75);
            }
            DecimalFormat decimalFormat = new DecimalFormat(".00");
            String string = decimalFormat.format(sugar);
            showSugar(string);
            return light;
        }
    
        /**
         * 计算数组的平均值
         *
         * @param array 数组
         * @return 返回平均值
         */
        public static float totalCount(float[] array){
            float total=0;
            for (float value : array) {
                total += value;
            }
            total = total / array.length;
            return total;
        }
    
        public void showSugar(String sugar){
            String string = String.format("测得糖度值为:%s Brix", sugar);
            sugarView.setText(string);
        }
    }
    

    xml界面代码如下

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@color/lightSteelBlue"
        xmlns:custom="http://schemas.android.com/apk/res-auto">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="40sp"
            android:textColor="@color/dimGray"
            android:text="@string/welcome"
            android:gravity="center"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="90sp"
            />
    
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/la"
            android:layout_gravity="right"
            />
    
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/logo"/>
    
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/la3"
            android:layout_marginTop="280dp"
            />
    
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/la2"
            android:layout_gravity="center_horizontal|bottom"
            android:layout_marginBottom="80dp"
            android:layout_marginLeft="155dp"
            />
    
        <Button
            android:id="@+id/takePicture"
            android:layout_width="180dp"
            android:layout_height="70dp"
            android:layout_gravity="center_horizontal|bottom"
            android:layout_marginBottom="160dp"
            android:background="@drawable/botton_style"
            android:gravity="center"
            android:text="@string/takePhoto"
            android:textSize="20sp" />
    
        <Button
            android:id="@+id/clearImage"
            android:layout_width="180dp"
            android:layout_height="70dp"
            android:layout_gravity="center_horizontal|bottom"
            android:background="@drawable/botton_style"
            android:layout_marginBottom="60dp"
            android:padding="20dp"
            android:text="@string/closePicture"
            android:textSize="17sp" />
    
        <com.example.appsrc.RoundImageView
            android:id="@+id/myCustom"
            android:layout_width="150dp"
            android:layout_height="150dp"
            android:layout_gravity="center"
            android:scaleType="centerInside"
            custom:border_inside_color="@color/ivory"
            custom:border_outside_color="@android:color/black"
            custom:border_thickness="2dp" />
    
        <TextView
            android:id="@+id/SugarText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#66666666"
            android:text="@string/currentSugar"
            android:gravity="center"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="230sp"
            android:padding="20dp"
            android:textColor="@android:color/white"
            android:textSize="18sp" />
    
    </FrameLayout>
    

    四、亮度值与糖度值的测试

    学校没钱买不起爱括,只能有损测量了,哎

    图片.png

    嗯 数据差不多就是这样,输入到测试公式就好了

    五、结语

    管他什么误差呢,做完就好还混了个奖是吧~~~

    相关文章

      网友评论

          本文标题:2021.8 第九届全国大学生光电竞赛

          本文链接:https://www.haomeiwen.com/subject/tjxebltx.html