当前位置: 代码迷 >> 综合 >> 传统图像处理的一般流程
  详细解决方案

传统图像处理的一般流程

热度:35   发布时间:2024-01-26 06:53:31.0

即便当前深度学习技术在图像处理领域发挥着越来越重要的作用,但是在某些特定的场合下,传统图像处理以计算快捷,耗费资源少等特点也发挥着不可替代的作用,这边文章就我一个项目,阐述下我的感想。

 

项目一: 目标检测

前景提取流程:

设置一个vector,先存放三张读入的第一帧 --》接下来读入的帧分别和vector中的每个图像相减并二值化(根据阈值区间),得到三个前景,三个前景做与操作 ,并得到前景像素点最多的索引和最少的索引--》判断背景是否有效 --》有效的话,背景就更新的缓 --》无效的话背景更新的快点(替换前景像素点最多的背景) --判断前景是否有效,循环。

#include "stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
#include"FgDetection.hpp"using namespace cv;
using namespace std;#define FRAME_DIFF_SIZE		3
#define REFER_IMG_SIZE		3
#define FRAME_INDEX(x)      (FRAME_DIFF_SIZE - (x) - 1)FgDetection::FgDetection(void):initialized(false),maxBgNonupdateCnt(100),validBackground(false),fgPixCnt(0),irrationalFgRatio(0.3),alpha(0.01),fgRatioForBgLearn(0.02f),bgLearnCnt(0),maxFgChangeFactor(1.0f),motionThreshold(0)
{
}
int FgDetection::Detect(Mat img, int timeInterval)
{Mat imgGray = img;double start = (double)getTickCount();//开始时间double totaltime;cvtColor(imgGray, imgGray, CV_BGR2GRAY);//全局变量 capture读入的一帧灰度图像frameImg = imgGray.clone();//新建图像数组,size = 3if (!initialized) //如果没有初始化.,用来声明一个数组来存放输读入的图片{for (int i = 0; i < FRAME_DIFF_SIZE; i++){frameImgList.push_back(imgGray);Background bg;Mat bgImg = imgGray.clone();bg.bgImg = bgImg.clone();bg.nonupdateCnt = maxBgNonupdateCnt;//存了三个第一帧图像,后续会使用第四帧减去第一帧bgList.push_back(bg);}initialized = true;}//将第一个元素拷贝一份到list尾部,这个数组在更新背景的时候没用到,目的就是保存当前三帧图形frameImgList.push_back(frameImgList.front());frameImgList.back() = frameImg.clone();frameImgList.erase(frameImgList.begin());//初始是falseif (!validBackground){//是否需要学习背景if (LearnBackground() != 0)  return -1;}//当读取到三帧的时候才会执行到这一个分支else{UpdateFgBg();//更新前景和背景}double finish = (double)getTickCount();//开始时间totaltime = (double)(finish - start) *1000/ getTickFrequency();//cout << "Current frame takes " << totaltime << "ms!" << endl;return 0;
}
//判断是否可以学习背景图像
int FgDetection::LearnBackground(void)
{const int minCount = REFER_IMG_SIZE;const int maxCount = REFER_IMG_SIZE * 5;bgLearnCnt++;//读了15帧还是静态的就退出if (bgLearnCnt > maxCount){std::cout << "Cannot get a valid background." << std::endl;bgLearnCnt = 0;return -1;}//是否可以提取到有效的前景if (UpdateFgBg() != 0) return -1;int nonZeroCnt;nonZeroCnt = countNonZero(foregroundImg); //计算前景像素数float ratio = (float)nonZeroCnt / (foregroundImg.cols * foregroundImg.rows);//执行到这一步,是读了三帧以后if ((ratio <= fgRatioForBgLearn) && (bgLearnCnt > minCount)){//设置标志位validBackground = true;bgLearnCnt = 0;fgPixCnt = nonZeroCnt;}return 0;
}int FgDetection::UpdateFgBg(void)
{if (frameImg.channels()  == 1){int minInd = 0, maxInd = 0;int minFgCnt = frameImg.cols * frameImg.rows;int maxFgCnt = 0;Mat DiffImg, ThreImg;std::vector<Mat> fgImgList;//初始化一个只存放二值化前景的图像数据for (int i = 0; i < REFER_IMG_SIZE; i++){Mat fgImg(cvSize(frameImg.cols, frameImg.rows), CV_8UC1,1);fgImgList.push_back(fgImg);}for (int i = 0; i < REFER_IMG_SIZE; i++){Mat tmpframeImg = frameImg.clone();absdiff(tmpframeImg, bgList[i].bgImg, DiffImg);		//图像绝对值做差threshold(DiffImg, fgImgList[i], 30, 255, THRESH_BINARY);//图像阈值化操作//非零像素点个数int CntNonZero = countNonZero(fgImgList[i]);if (CntNonZero < minFgCnt) //挑选出前景点最少的背景图{minFgCnt = CntNonZero;minInd = i;}if (CntNonZero > maxFgCnt) //挑选出前景点最多的背景图{maxFgCnt = CntNonZero;maxInd = i;}if (i == 0)   //foregroundImg初始化为第一张前景图{fgImgList[0].copyTo(foregroundImg);}else  //后续计算得到的前景图与foregroundImg进行与操作{bitwise_and(fgImgList[i], foregroundImg, foregroundImg);}bgList[i].nonupdateCnt++;  //这个变量做什么,统计背景图用了多少次?}validBgInd = minInd;   //前景点最少的背景图像是可用背景?isRationalFrame = true;//计算前景像素率int fgCnt = countNonZero(foregroundImg);float fgRatio = (float)fgCnt / (frameImg.cols * frameImg.rows);//cout << "fgCnt:" << fgCnt << "fgRatio" << fgRatio <<endl;int prevFgCnt = fgPixCnt; //上一帧图像的前景像素数if (fgPixCnt < 10) prevFgCnt = 10;fgPixCnt = fgCnt;		  //此帧图像的前景像素数if (fgCnt < 10) fgCnt = 10;float fgChangeFactor = (float)fgCnt / prevFgCnt; //前景之间的变化率if (fgChangeFactor < 1) fgChangeFactor = 1.0f / fgChangeFactor;//如果(前景像素率>不合理阈值)AND(前景的变化率>最大)if ((fgRatio > irrationalFgRatio) && (fgChangeFactor > maxFgChangeFactor)){validBackground = false;isRationalFrame = false;}//如果满足前景像素率和前景变化率条件//腐蚀,膨胀*2Mat element_fg = getStructuringElement(MORPH_RECT, Size(3, 3));erode(foregroundImg, foregroundImg, element_fg);dilate(foregroundImg, foregroundImg, element_fg);dilate(foregroundImg, foregroundImg, element_fg);/*//计算motion图像Mat fdDiffImg(frameImg.rows, frameImg.cols, CV_8UC1);Mat tmp32FImg(frameImg.rows, frameImg.cols, CV_32FC1);Mat tmp8UImg(frameImg.rows, frameImg.cols, CV_8UC1);tmp32FImg = frameImgList[FRAME_INDEX(0)];motionImg = tmp32FImg.clone();motionImg = 0;for (int i = 0; i < FRAME_DIFF_SIZE - 1; i++){fdDiffImg = frameImgList[FRAME_INDEX(i + 1)].clone();absdiff(tmp32FImg, fdDiffImg, fdDiffImg);motionThreshold = 10; // 这个是可调节灵敏度threshold(fdDiffImg, tmp8UImg, (double)motionThreshold, 255, THRESH_BINARY);//图像阈值化操作fgCnt = countNonZero(tmp8UImg);cout << "fgCnt-tmp8UImg:" << fgCnt  << endl;bitwise_or(motionImg, tmp8UImg, motionImg);}Mat a = motionImg.clone();//腐蚀,膨胀*2Mat element_motion = getStructuringElement(MORPH_RECT, Size(3, 3));erode(motionImg, motionImg, element_motion);dilate(motionImg, motionImg, element_motion);dilate(motionImg, motionImg, element_motion);*/if (validBackground){//生成检测区域}else{// Set the alpha 0.01 image for background updating.cv::Mat alphaImg(frameImg.rows, frameImg.cols, CV_8UC1, Scalar(1)); //gray }//更新背景if (validBackground){//For object tracking, we need slow alpha for foreground, we don't need for smoke detection to reduce false alarms.Mat tmp32FImg = frameImg.clone();bgList[minInd].bgImg = bgList[minInd].bgImg * (1-0.001)  + tmp32FImg * 0.001;//bgList[minInd].bgImg = bgList[minInd].bgImg  + (tmp32FImg- bgList[minInd].bgImg) * 0.01;bgList[minInd].nonupdateCnt = 0;}if ((!validBackground)|| (bgList[maxInd].nonupdateCnt > 100)){// Set the alpha image for background updating.cv::Mat alphaImg(frameImg.rows, frameImg.cols, CV_8UC1, Scalar(0.9)); //gray alpha = 0.3;if (validBackground){cv::Mat alphaImg(frameImg.rows, frameImg.cols, CV_8UC1, Scalar(0.001)); //gray bitwise_and(alphaImg, alphaImg, alphaImg,foregroundImg);alpha = 0.8;}Mat tmp32FImg = frameImg.clone();//tmp32FImg = bgList[maxInd].bgImg; //前景最多的背景图减去当前帧bgList[maxInd].bgImg = bgList[maxInd].bgImg *(1-alpha)+ tmp32FImg* alpha;//bgList[maxInd].bgImg = bgList[maxInd].bgImg + (tmp32FImg - bgList[maxInd].bgImg) * alpha;bgList[maxInd].nonupdateCnt = 0;}imshow("bg0", bgList[0].bgImg);imshow("bg1", bgList[1].bgImg);imshow("bg2", bgList[2].bgImg);// printf("min:%d,max %d\n", minInd, maxInd);//imshow("bg2", bgList[2].bgImg);//imshow("foregroundImg", foregroundImg);//waitKey(1);}return 0;
}

流程:提取前景 --》 把整张图像分为N个block(每个block是一个结构体) --》 得到优效的背景(前景像素点个数占比全局像素点个数小于某个阈值,连续15帧一直得不到优效背景就退出)--》 得到有效背景后,统计每个block中前景像素点是否超过25个 ,超过计数变量加1,连续统计50帧,如果有其中10帧像素点超过25个,标记该block --》 对标记的block,进行特征计算(HSV颜色,LBP特征,纹理,能量特征) --》 每种特征都满足的话,设置计数变量++- --》如果50帧里,计数变量大于10,这个区域就代表有目标 --》每个block中的变量清0

  相关解决方案