2016-10-24 20:31:02 Kazichs 阅读数 8312

前几天写了一个小的项目关于:当手机处于静止状态时,识别是否动或者前方有不同物体

MainActivity

public class MainActivity extends Activity implements SurfaceHolder.Callback,
        PreviewCallback {

    // 定义对象
    private SurfaceView mSurfaceview = null; // SurfaceView对象:(视图组件)视频显示
    private SurfaceHolder mSurfaceHolder = null; // SurfaceHolder对象:(抽象接口)SurfaceView支持类
    private Camera mCamera;
    private Camera.Parameters parameters = null;
    private Bitmap bitmap;// 原图
    private Bitmap tempBitmap;// temp bitmap
    private Bitmap bitmap_;//处理后的bitmap
    private Bitmap bgBitmap;//背景图
    private Bitmap bgBitmap_;//处理后的背景图片
    private ImageView img;
    private SurfaceView view;
    private long times = 0l;//连续多久不动时间
    private long indexFrame = 0l;
    private static final String TAG ="MainActivity";
    private long times_ = 0l;//temp time    
    private int police_time = 25;//持续时间
    private int police_time_ = 10;//持续时间
    private long times_2 = 0l;//报警确认次数
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.camera_layout);
        init();
    }

    // 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 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...");

        }


    // 初始化控件
    private void init() {

        // SurfaceView
        view = (SurfaceView) findViewById(R.id.surface_view);
        // 照相机预览的空间
        view.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        view.getHolder().setFixedSize(1920, 1080); // 设置Surface分辨率
        view.getHolder().setKeepScreenOn(true);// 屏幕常亮
        view.getHolder().addCallback(this);// 为SurfaceView的句柄添加一个回调函数

        // ImageView
        img = (ImageView) findViewById(R.id.img_res);
    }

    // SurfaceHoder.Callback
    // 当SurfaceView/预览界面的格式和大小发生改变时,该方法被调用
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        // TODO Auto-generated method stub
        parameters = mCamera.getParameters(); // 获取各项参数
        mCamera.setParameters(parameters);
        parameters.setPictureFormat(PixelFormat.JPEG); // 设置图片格式
        parameters.setPreviewSize(width, height); // 设置预览大小
        parameters.setPreviewFrameRate(5); // 设置每秒显示4帧
        parameters.setPictureSize(width, height); // 设置保存的图片尺寸
        parameters.setJpegQuality(80); // 设置照片质量
        mCamera.setPreviewCallback(this);
        startFocus();
    }

    // SurfaceView启动时/初次实例化,预览界面被创建时,该方法被调用。
    @Override
    public void surfaceCreated(SurfaceHolder mSurfaceHolder) {
        // TODO Auto-generated method stub
        try {
            mCamera = Camera.open(1); // 打开摄像头
            mCamera.setPreviewDisplay(mSurfaceHolder); // 设置用于显示拍照影像的SurfaceHolder对象
            mCamera.setDisplayOrientation(getPreviewDegree(MainActivity.this));
            mCamera.startPreview(); // 开始预览
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 提供一个静态方法,用于根据手机方向获得相机预览画面旋转的角度
    public static int getPreviewDegree(Activity activity) {
        // 获得手机的方向
        int rotation = activity.getWindowManager().getDefaultDisplay()
                .getRotation();
        int degree = 0;
        // 根据手机的方向计算相机预览画面应该选择的角度
        switch (rotation) {
        case Surface.ROTATION_0:
            degree = 90;
            break;
        case Surface.ROTATION_90:
            degree = 0;
            break;
        case Surface.ROTATION_180:
            degree = 270;
            break;
        case Surface.ROTATION_270:
            degree = 180;
            break;
        }  
        return degree;
    }

    // SurfaceView销毁时,该方法被调用
    @Override
    public void surfaceDestroyed(SurfaceHolder arg0) {
        // TODO Auto-generated method stub
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);
            mCamera.release(); // 释放照相机
            mCamera = null;
        }
    }

    // PreviewCallback
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        // TODO Auto-generated method stub
        if (indexFrame++ % 6 != 0)
            return;
        Size size = camera.getParameters().getPreviewSize();
        try {
            YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width,
                    size.height, null);
            if (image != null) {
                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                image.compressToJpeg(new Rect(0, 0, size.width, size.height),
                        80, stream);

                Bitmap bmp = BitmapFactory.decodeByteArray(
                        stream.toByteArray(), 0, stream.size());
                // **********************
                // 因为图片会放生旋转,因此要对图片进行旋转到和手机在一个方向上
                bmp = rotaingImageView(-90, bmp);
                // 图片太大处理较慢,就把图片缩放裁剪
                Matrix matrix = new Matrix();
                matrix.postScale(0.125f, 0.125f); // 长和宽缩小的比例
                bitmap = bmp.createBitmap(bmp, 0, 0, size.height, size.width,
                        matrix, true);

                bitmap_ = procSrc2Gray(bitmap);//灰度
                bitmap_ = changeBitmap(bitmap);//二值
                //报警
                getPolice();
                // **********************************
                stream.close();
            }
        } catch (Exception ex) {
            Log.e("Sys", "Error:" + ex.getMessage());
        }
    }

    // 自动对焦
    Timer timer = new Timer(true);
    TimerTask task = new TimerTask() {
        public void run() {
            // 每次需要执行的代码放到这里面
            // 实现自动对焦
            mCamera.autoFocus(null);
        }
    };

    public void startFocus() {
        timer.schedule(task, 0, 3000);
    }

    // 旋转
    public Bitmap rotaingImageView(int angle, Bitmap bitmap) {
        // 旋转图片 动作
        Matrix matrix = new Matrix();
        matrix.postRotate(angle);
        // 创建新的图片
        Bitmap bm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
                bitmap.getHeight(), matrix, true);
        return bm;
    }

    // 比较图片
        public boolean isEquals(Bitmap b1, Bitmap b2) {
            int xCount = b1.getWidth();
            int yCount = b1.getHeight();
            int number = 0;
            for (int x = 0; x < xCount; x++) {
                for (int y = 0; y < yCount; y++) {
                    // 比较每个像素点颜色
                    if (b1.getPixel(x, y) != b2.getPixel(x, y)) {
                        number++;
                    }
                }
            }
            if(number < 500) return true;
            return false;
        }

    //灰度化
    public Bitmap procSrc2Gray(Bitmap bm){
       Mat rgbMat = new Mat();  
       Mat grayMat = new Mat();  
       Bitmap graybm = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Config.ARGB_8888);  
       Utils.bitmapToMat(bm, rgbMat);//convert original bitmap to Mat, R G B.  
       Imgproc.cvtColor(rgbMat, grayMat, Imgproc.COLOR_RGB2GRAY);//rgbMat to gray grayMat
       Utils.matToBitmap(grayMat, graybm);
       return graybm;
    }
    //二值化
    public Bitmap changeBitmap(Bitmap bm) {
        Mat rgbMat = new Mat();  
        Mat grayMat = new Mat();  
        Bitmap graybm = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Config.ARGB_8888);  
        Utils.bitmapToMat(bm,rgbMat);
        Imgproc.threshold(rgbMat,grayMat,100,255,Imgproc.THRESH_BINARY);
        Utils.matToBitmap(grayMat,graybm);
        return graybm;
    }

 // 图像计算
    public Bitmap getPicture(Bitmap bmp1, Bitmap bmp2) {

        /*
         * pixels 接收位图颜色值的数组 offset 写入到pixels[]中的第一个像素索引值 stride
         * pixels[]中的行间距个数值(必须大于等于位图宽度)。可以为负数 x   从位图中读取的第一个像素的x坐标值。 y
         * 从位图中读取的第一个像素的y坐标值 width   从每一行中读取的像素宽度 height    读取的行数
         */
        int m_ImageWidth, m_ImageHeigth;
        m_ImageWidth = bmp1.getWidth();
        m_ImageHeigth = bmp1.getHeight();
        int m_Bmp1Pixel[], m_Bmp2Pixel[], m_Bmp3Pixel[];
        m_Bmp1Pixel = new int[m_ImageWidth * m_ImageHeigth];
        m_Bmp2Pixel = new int[m_ImageWidth * m_ImageHeigth];
        m_Bmp3Pixel = new int[m_ImageWidth * m_ImageHeigth];
        bmp1.getPixels(m_Bmp1Pixel, 0, m_ImageWidth, 0, 0, m_ImageWidth,
                m_ImageHeigth);
        bmp2.getPixels(m_Bmp2Pixel, 0, m_ImageWidth, 0, 0, m_ImageWidth,
                m_ImageHeigth);
        System.out.println("AAAAAAAAAAAA2");
        for (int i = 0; i < m_ImageWidth * m_ImageHeigth; i++) {
            if (m_Bmp1Pixel[i] != m_Bmp2Pixel[i]) {
                m_Bmp3Pixel[i] = m_Bmp2Pixel[i];
            }
        }
        System.out.println("AAAAAAAAAAAA3");
        Bitmap pro = Bitmap.createBitmap(m_ImageWidth, m_ImageHeigth,
                Bitmap.Config.ARGB_8888);
        pro.setPixels(m_Bmp3Pixel, 0, m_ImageWidth, 0, 0, m_ImageWidth,
                m_ImageHeigth);
        System.out.println("AAAAAAAAAAAA4");
        return pro;
    }

    //报警系统
    public void getPolice(){
        if(tempBitmap != null){
            if (isEquals(tempBitmap, bitmap_) == true) {
                times++;
                times_2 = 0;
                Log.e("MainActivity", "number:" + times + ";" );
            }else{
                times_ = 0;
            }
        }
        if(tempBitmap != null && times < police_time){
            if (isEquals(tempBitmap, bitmap_) == false){
                times = times_;
            }
        }
        //Toast.makeText(MainActivity.this, "number:" + times, Toast.LENGTH_LONG).show();
        tempBitmap = bitmap_;
        if(times == police_time){
            bgBitmap = bitmap;//背景图
            bgBitmap_ = procSrc2Gray(bgBitmap);//灰度
            bgBitmap_ = changeBitmap(bgBitmap);//二值
            //震动提醒
//          Vibrator vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
//          vibrator.vibrate(1000);
            //声音提醒
            NotificationManager manger = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 
            Notification notification = new Notification(); 
            //自定义声音   声音文件放在ram目录下,没有此目录自己创建一个
            //notification.sound=Uri.parse("android.resource://" + getPackageName() + "/" +R.raw.mm); 
            notification.defaults=Notification.DEFAULT_SOUND;//手机系统提示音
            manger.notify(1, notification);
            Toast.makeText(MainActivity.this, "开始执行程序", Toast.LENGTH_LONG).show();
        }

        if(times >police_time){
                Log.e(TAG, "action");
                // 有结果,则终止线程
                if(isEquals(bgBitmap_, bitmap_) == false){
                    times_2++;
                    if(times_2 > police_time_){
                        // 有结果,则终止线程
                        times = times_;
                        Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:"
                                + "1111"));
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        startActivity(intent);
                    }
                }
        }
    }

    //报警确认
}

layout

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <SurfaceView
        android:id="@+id/surface_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

    <ImageView
        android:id="@+id/img_res"
        android:scaleType="centerInside"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_gravity="center_horizontal|bottom" />


</FrameLayout>

这地方有几个难点:

1.  如何实现相机帧预览(即相机处于预览状态时,每帧图片多能得到);

关键词 :PreviewCallback
对应的方法:onPreviewFrame
// PreviewCallback
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        // TODO Auto-generated method stub
        if (indexFrame++ % 6 != 0)//一秒六帧。可以增加图片处理速度
            return;
        Size size = camera.getParameters().getPreviewSize();
        try {
            YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width,
                    size.height, null);
            if (image != null) {
                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                image.compressToJpeg(new Rect(0, 0, size.width, size.height),
                        80, stream);

                Bitmap bmp = BitmapFactory.decodeByteArray(
                        stream.toByteArray(), 0, stream.size());
                // **********************
                // 因为图片会放生旋转,因此要对图片进行旋转到和手机在一个方向上
                bmp = rotaingImageView(-90, bmp);
                // 图片太大处理较慢,就把图片缩放裁剪
                Matrix matrix = new Matrix();
                matrix.postScale(0.125f, 0.125f); // 长和宽缩小的比例
                bitmap = bmp.createBitmap(bmp, 0, 0, size.height, size.width,
                        matrix, true);

                bitmap_ = procSrc2Gray(bitmap);//灰度
                bitmap_ = changeBitmap(bitmap);//二值
                //报警
                getPolice();
                // **********************************
                stream.close();
            }
        } catch (Exception ex) {
            Log.e("Sys", "Error:" + ex.getMessage());
        }
    }

其中,本身手机拍照图片会很大,图片对应显示就会很慢,人眼感觉就会一卡一卡的,除了处理每秒几帧,这里也图片裁切,缩小了

// 图片太大处理较慢,就把图片缩放裁剪
                Matrix matrix = new Matrix();
                matrix.postScale(0.125f, 0.125f); // 长和宽缩小的比例
                bitmap = bmp.createBitmap(bmp, 0, 0, size.height, size.width,
                        matrix, true);

两个方法:postScale();createBitmap()

2.  怎么去识别相机如何不动;
思路:①将每帧处理的图片保存为tempbitmap ;②下一帧的图片与之比较;③相同times++,不同times = 0;④当times = x 时,即手机不动了。
//手机画面确认不动
if(tempBitmap != null){
            if (isEquals(tempBitmap, bitmap_) == true) {
                times++;
                times_2 = 0;
                Log.e("MainActivity", "number:" + times + ";" );
            }else{
                times_ = 0;
            }
        }
        if(tempBitmap != null && times < police_time){
            if (isEquals(tempBitmap, bitmap_) == false){
                times = times_;
            }
        }
3.  相机不动时,如何确认前方有障碍物或者手机在动;
    思路相同,就不详细诉说了,代码多有

当时除了这些问题还有一些简单的问题卡了我好久,

1.相机如何自动对焦(要用时调用starFocus()):

// 自动对焦
    Timer timer = new Timer(true);
    TimerTask task = new TimerTask() {
        public void run() {
            // 每次需要执行的代码放到这里面
            // 实现自动对焦
            mCamera.autoFocus(null);
        }
    };

    public void startFocus() {
        timer.schedule(task, 0, 3000);
    }

2.如何比较两组图片是否为相同(我能力有限不能让所有rgb值一样,所以就取了一个约值,2%-3%)

处理最重要的地方:将比较的两幅图片,灰度化并且二值化,不然你会很惨的

    // 比较图片
        public boolean isEquals(Bitmap b1, Bitmap b2) {
            int xCount = b1.getWidth();
            int yCount = b1.getHeight();
            int number = 0;
            for (int x = 0; x < xCount; x++) {
                for (int y = 0; y < yCount; y++) {
                    // 比较每个像素点颜色
                    if (b1.getPixel(x, y) != b2.getPixel(x, y)) {
                        number++;
                    }
                }
            }
            if(number < 500) return true;
            return false;
        }

二值化,灰度化:

//灰度化
    public Bitmap procSrc2Gray(Bitmap bm){
       Mat rgbMat = new Mat();  
       Mat grayMat = new Mat();  
       Bitmap graybm = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Config.ARGB_8888);  
       Utils.bitmapToMat(bm, rgbMat);//convert original bitmap to Mat, R G B.  
       Imgproc.cvtColor(rgbMat, grayMat, Imgproc.COLOR_RGB2GRAY);//rgbMat to gray grayMat
       Utils.matToBitmap(grayMat, graybm);
       return graybm;
    }
    //二值化
    public Bitmap changeBitmap(Bitmap bm) {
        Mat rgbMat = new Mat();  
        Mat grayMat = new Mat();  
        Bitmap graybm = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Config.ARGB_8888);  
        Utils.bitmapToMat(bm,rgbMat);
        Imgproc.threshold(rgbMat,grayMat,100,255,Imgproc.THRESH_BINARY);
        Utils.matToBitmap(grayMat,graybm);
        return graybm;
    }

这里关于opencv的运用前面的博客有详细说明。

2019-07-30 09:41:27 weixin_39444552 阅读数 196

先放几张效果图

正常
阴影下
有遮挡
暗光+重叠(由于阈值设置,过小的柑橘未识别)

过侵蚀的原理

要识别被障碍物遮挡的物体,往往只需要对物体的部分进行识别即可判断是否是要识别的物体,由此在识别过程中,为了分离物体与障碍物,可以对识别主体进行过度的侵蚀,只检测模板中最重要的特征并进行标注,而不影响识别物体的准确率。

要解决的问题及解决思路

  1. 根据柑橘和背景的颜色差异进行识别

    解决思路: 实验表明,在YCbCr颜色空间中,对Cr分量使用最大类间方差法(Otsu) 能较好地将成熟柑橘与背景图片分离开来。

  2. 分离互相重叠的柑橘
    解决思路: 通过低阈值的敏感Canny算子,对重叠柑橘的边界进行识别,然后对边界进行过侵蚀(即只侵蚀不膨胀),由此带来的后果是边界尽可能扩大,而识别区域变小,但在可以接受的范围之内。

  3. 识别被叶子遮挡柑橘

    解决思路:利用检测到的边缘,通过凸包算法识别凸包并进行填充,亦可弥补过侵蚀带来的空洞。

开发平台及用到的第三方库

开发平台: Eclipse
程序设计语言:JAVA
开发工具:opencv开源代码库

参考论文

[1]蔡健荣,周小军,李玉良,范军.基于机器视觉自然场景下成熟柑橘识别[J].农业工程学报,2008(01):175-178.

[2]吴定中,邹湘军,熊俊涛,陈丽娟,彭红星.面向复杂背景环境目标的快速识别研究[J].农机化研究,2014,36(01):178-183.

识别流程

在这里插入图片描述

步骤效果及注意事项

  1. 原始图像
    在这里插入图片描述

  2. 颜色筛选

    先用以下函数将原始图片由BGR空间转换YCrCb空间

    Imgproc.cvtColor(src, dst, Imgproc.COLOR_BGR2YCrCb);
    

    再提取Cr分量,对分量调用Ostu阈值分割,注意这里得到的是目标区域的二值图,将其作为掩模与原图进行与运算即可提取出目标区域。

    Imgproc.threshold(img_cr, dst, 0, 255, Imgproc.THRESH_OTSU);
    

在这里插入图片描述
3. 中值模糊

这里需要进行一次滤波是为了减少过多噪音Canny边缘检测的影响。
在均值滤波、中值滤波、高斯滤波中采取不会丢失重叠边缘的中值滤波。
在这里插入图片描述
4. Canny边缘检测

跟阈值分割一样,以检测到的边缘图片做掩模加深原图边缘。
在这里插入图片描述在这里插入图片描述
5. 过侵蚀
在这里插入图片描述
6. 开运算
在这里插入图片描述
7. 灰度化、二值化

先灰度化将三通道转为单通道,再根据灰度值二值化。
在这里插入图片描述
8. 凸包填充

识别过程不需要进行闭运算进行空洞填充,因为在保留边缘的条件下可直接识别凸包进行填充,注意填充凸包后要重绘凸包边界,防止边缘连接,否则就会如下图:
错误示范
正确示范:
在这里插入图片描述
9. 椭圆拟合

主要调用以下两个函数:

Imgproc.findContours(dst, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE,
                new Point(0, 0));
Imgproc.fitEllipse(dst); 	//调用此函数前要判断轮廓点超过5个,否则会报错

这里面积较小的柑橘未识别出来,是因为我将面积小于最大连通区域1/5的连通区域当成噪音去除了。
在这里插入图片描述
10. 结果图像
在这里插入图片描述

优点

  1. 为解决柑橘识别问题提供一种新的思路。
  2. 算法简单,运行速度快。
  3. 能适应大多数环境下的识别。

缺点

  1. 在阳光直射条件下(颜色呈完全的白色)有可能会在颜色筛选时出现较大空洞,有时不能完全填充。
  2. 对被障碍物分割成两块或多块的区域无法正确识别。
  3. 对于一套函数的阈值只适用于一段距离的识别(如当前系统只适用于近景),鲁棒性较差。
  4. 过侵蚀带来的识别区域的丢失导致不能准确定位柑橘的质心。

作业阶段,暂不开源,望见谅。。

2019-07-27 15:08:27 qq_42444944 阅读数 212
  1. 知道目标物体的坐标,根据目标物体的坐标。和目标车库的坐标。两个坐标位置进行判断。
  2. 根据小车要匀速行驶。根据小车移动的时间*速度来判断小车位置
  3. 小车先找到小铁块,吸上以后,将车头方向指向车库方向
  4. 如果小车坐标是(2,1),车库坐标是(3,4)
  5. 移动y坐标,这个题目是向车库方向移动3个坐标,每个方块一个时间,三个固定时间就是一段距离,
  6. 如果遇到障碍物,就右转判断前后左右哪个方向的距离值大,就向那个方向行走一个格的时间,
  7. 然后判断坐标是在左右那个方向,如果车库横坐标>小车坐标,就右转,否则左转,移动到车库方向铁块
  8. 那么根据算法,
2018-07-04 22:40:48 WangchangIsHere 阅读数 436

要让小车正常安全地驾驶,最重要的事情就是识别出障碍物以及其存在的位置。SDK能输出mat格式的灰度图像,一个想法是图像显著性区域的提取。
在走廊环境下,如果有障碍物存在,有很大可能是一个图像的显著性区域。(比如边缘特征明显,颜色特征明显)所以提取显著性区域成为了一个油然而生的想法。


1.AC算法

void SRD_AC(Mat &src,int MinR2, int MaxR2,int Scale){  
    Mat Lab;  
    cvtColor(src, Lab, CV_BGR2Lab);   

    int row=src.rows,col=src.cols;  
    int Sal_org[960][1280];  
    memset(Sal_org,0,sizeof(Sal_org));  

    Mat Sal=Mat::zeros(src.size(),CV_8UC1 );  

    Point3_<uchar>* p;  
    Point3_<uchar>* p1;  
    int val;  
    Mat filter;  

    int max_v=0;  
    int min_v=1<<28;  
    for (int k=0;k<Scale;k++){  
        int len=(MaxR2 - MinR2) * k / (Scale - 1) + MinR2;  
        blur(Lab, filter, Size(len,len ));  
        for (int i=0;i<row;i++){  
            for (int j=0;j<col;j++){  
                p=Lab.ptr<Point3_<uchar> > (i,j);  
                p1=filter.ptr<Point3_<uchar> > (i,j);  

                val=sqrt( (p->x - p1->x)*(p->x - p1->x)+ (p->y - p1->y)*(p->y-p1->y) + (p->z - p1->z)*(p->z - p1->z) );  
                Sal_org[i][j]+=val;  
                if(k==Scale-1){  
                    max_v=max(max_v,Sal_org[i][j]);  
                    min_v=min(min_v,Sal_org[i][j]);  
                }  
            }  
        }  
    }  

    cout<<max_v<<" "<<min_v<<endl;  
    int X,Y;  
    for (Y = 0; Y < row; Y++)  
    {  
        for (X = 0; X < col; X++)  
        {  
            if(max_v - min_v == 0)  Sal.at<uchar>(Y,X) =0;
            else Sal.at<uchar>(Y,X) = (Sal_org[Y][X] - min_v)*255/(max_v - min_v);        //    计算全图每个像素的显著性  
            //Sal.at<uchar>(Y,X) = (Dist[gray[Y][X]])*255/(max_gray);        //    计算全图每个像素的显著性  
        }  
    }  
    imshow("sal",Sal);  
    waitKey(10);  
}

FC算法:

void SalientRegionDetectionBasedonLC(Mat &src){  
    int HistGram[256]={0};  
    int row=src.rows,col=src.cols;  
    int gray[row][col];     //这一处要修改,因为不能用变量声明一个数组
    //int Sal_org[row][col];  
    int val;  
    Mat Sal=Mat::zeros(src.size(),CV_8UC1 );  
    Point3_<uchar>* p;  
    for (int i=0;i<row;i++){  
        for (int j=0;j<col;j++){  
            p=src.ptr<Point3_<uchar> > (i,j);  
            val=(p->x + (p->y) *2 + p->z)/4;  
            HistGram[val]++;  
            gray[i][j]=val;  
        }  
    }  

    int Dist[256];  
    int Y,X;  
    int max_gray=0;  
    int min_gray=1<<28;  
    for (Y = 0; Y < 256; Y++)  
    {  
        val = 0;  
        for (X = 0; X < 256; X++)   
            val += abs(Y - X) * HistGram[X];                //    论文公式(9),灰度的距离只有绝对值,这里其实可以优化速度,但计算量不大,没必要了  
        Dist[Y] = val;  
        max_gray=max(max_gray,val);  
        min_gray=min(min_gray,val);  
    }  


    for (Y = 0; Y < row; Y++)  
    {  
        for (X = 0; X < col; X++)  
        {  
            if(max_v - min_v == 0)  Sal.at<uchar>(Y,X) = 0;
            else Sal.at<uchar>(Y,X) = (Sal_org[Y][X] - min_v)*255/(max_v - min_v);        //    计算全图每个像素的显著性  
            //Sal.at<uchar>(Y,X) = (Dist[gray[Y][X]])*255/(max_gray);        //    计算全图每个像素的显著性  

        }  
    }  
    imshow("sal",Sal);  
    waitKey(10);  

}  

FT算法:

void SRD_FT(Mat &src){  
    Mat Lab;  
    cvtColor(src, Lab, CV_BGR2Lab);   

    int row=src.rows,col=src.cols;  

    int Sal_org[960][1280];  
    memset(Sal_org,0,sizeof(Sal_org));  

    Point3_<uchar>* p;  

    int MeanL=0,Meana=0,Meanb=0;  
    for (int i=0;i<row;i++){  
        for (int j=0;j<col;j++){  
            p=Lab.ptr<Point3_<uchar> > (i,j);  
            MeanL+=p->x;  
            Meana+=p->y;  
            Meanb+=p->z;  
        }  
    }  
    MeanL/=(row*col);  
    Meana/=(row*col);  
    Meanb/=(row*col);  

    GaussianBlur(Lab,Lab,Size(3,3),0,0);  

    Mat Sal=Mat::zeros(src.size(),CV_8UC1 );  

    int val;  

    int max_v=0;  
    int min_v=1<<28;  

    for (int i=0;i<row;i++){  
        for (int j=0;j<col;j++){  
            p=Lab.ptr<Point3_<uchar> > (i,j);  
            val=sqrt( (MeanL - p->x)*(MeanL - p->x)+ (p->y - Meana)*(p->y-Meana) + (p->z - Meanb)*(p->z - Meanb) );  
            Sal_org[i][j]=val;  
            max_v=max(max_v,val);  
            min_v=min(min_v,val);         
        }  
    }  

    cout<<max_v<<" "<<min_v<<endl;  
    int X,Y;  
    for (Y = 0; Y < row; Y++)  
    {  
        for (X = 0; X < col; X++)  
        {   if(max_v - min_v == 0)  Sal.at<uchar>(Y,X) = 0;
            else Sal.at<uchar>(Y,X) = (Sal_org[Y][X] - min_v)*255/(max_v - min_v);        //    计算全图每个像素的显著性  
            //Sal.at<uchar>(Y,X) = (Dist[gray[Y][X]])*255/(max_gray);        //    计算全图每个像素的显著性  
        }  
    }  
    imshow("sal",Sal);  
    waitKey(10);  
}  

关于原理,参数说明可以参考以下几篇文章,笔者就不抛砖引玉了:
https://www.cnblogs.com/Imageshop/p/3889332.html
https://blog.csdn.net/cai13160674275/article/details/72991049


此外我还找到一个有意思的小应用,用于展示集中显著性提取方法的效果:
http://files.cnblogs.com/Imageshop/salientregiondetection.rar

没有更多推荐了,返回首页