opencv_色彩深度_動態歷史影像(Motion History Image)效果
【運動歷史影像(MHI)】

========================================================
色彩深度(color depth)
色彩深度(color depth) : 用來表示一個像素所佔用的位元數。
視頻幀緩衝區中儲存1像素的顏色所用的位元數目,
它也稱為位元/像素(bpp / bit per pixel)。
色彩深度越高 , 可用的顏色就越多。
==================================================================
τ(tau) 【念法:ʹtau 】: τ(小寫)代表 「一個時間區間」,從幀數的角度決定了運動的時間範圍
Ψ(psi) /【念法:ʹpsaɪ】: Ψ(x, y, t)為更新函數,可由幀間差、圖像差分或光流等多種方法定義
δ(delta) / 【念法: ʹdɛltə 】 : 為衰退參數
先試著讀取一張圖片
這裡我用位於C槽的lena.jpg來做測試
<第一階段小測試>
另外一些imread()函數內部搭配的參數
CV_LOAD_IMAGE_ANYCOLOR / 保持不變(原本圖像捨麼顏色就捨麼顏色)
src = imread("C:\\lena.jpg", 1);
src = imread("C:\\lena.jpg");
src = imread("C:\\lena.jpg", CV_LOAD_IMAGE_ANYCOLOR);
CV_LOAD_IMAGE_COLOR // 彩色
CV_LOAD_IMAGE_GRAYSCALE// 灰階
=======================================================
<第二階段小測試>
void updateMotionHistory(InputArray silhouette,
InputOutputArray mhi,
double timestamp,
double duration )
Parameters:
最後是演算法部分整合效果
程式碼

========================================================
色彩深度(color depth)
色彩深度(color depth) : 用來表示一個像素所佔用的位元數。
視頻幀緩衝區中儲存1像素的顏色所用的位元數目,
它也稱為位元/像素(bpp / bit per pixel)。
色彩深度越高 , 可用的顏色就越多。
==================================================================
運動歷史圖像(MHI): 一種基於視覺的模板方法,通過計算時間段內同一位置的像素變化,將目標運動情況以圖像亮度的形式表現出來。
MHI圖像可以表徵人體在一個動作過程中最近的動作情況,這使得MHI被廣泛應用於動作識別領域。
H為運動歷史圖像素的強度值,H (x, y, t) 可以由更新函數計算得出:
τ(tau) 【念法:ʹtau 】: τ(小寫)代表 「一個時間區間」,從幀數的角度決定了運動的時間範圍
Ψ(psi) /【念法:ʹpsaɪ】: Ψ(x, y, t)為更新函數,可由幀間差、圖像差分或光流等多種方法定義
δ(delta) / 【念法: ʹdɛltə 】 : 為衰退參數
先試著讀取一張圖片
這裡我用位於C槽的lena.jpg來做測試
<第一階段小測試>
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include<opencv/cv.h> | |
#include<opencv/highgui.h> | |
using namespace cv; | |
/** 函式宣告 */ | |
int main() | |
{ | |
//Mat map = imread("C:\lena.jpg", CV_LOAD_IMAGE_ANYCOLOR | CV_LOAD_IMAGE_ANYDEPTH); | |
Mat src,depthImage; | |
//depthImage = cv::imread("C:\\Users\\Mcu\\Desktoplena.jpg", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR); // Read the file | |
//depthImage = imread("C:\\lena.jpg" , 0 ); // gray if the flag = 0 | |
//depthImage = imread("C:\\lena.jpg", 1 ); // color if the flag = 1 | |
/*stage1*/ | |
src = imread("C:\\lena.jpg"); | |
namedWindow("stage1_lena剛載入", 0); | |
// namedWindow("視窗指定命名",flag); // flag=0可自動調適視窗大小 flag=1不行 | |
imshow("stage1_lena剛載入" , src); | |
/*stage2*/ | |
src.copyTo(depthImage); | |
namedWindow("stage2_複製給depthImage結果", 0); | |
imshow("stage2_複製給depthImage結果", depthImage); | |
Mat t1,t1_5 ,t2, t3, t4, t5, t6, t7, t8 , t9 , t10 , t11 , t12 , t13 , t14; | |
src.copyTo(t1); | |
src.copyTo(t2); | |
src.copyTo(t3); | |
src.copyTo(t4); | |
src.copyTo(t5); | |
src.copyTo(t6); | |
src.copyTo(t7); | |
src.copyTo(t8); | |
src.copyTo(t9); | |
src.copyTo(t10); | |
src.copyTo(t11); | |
/*stage3*/ | |
//Signed 16bits | |
/*=============================================================================*/ | |
t1.convertTo(t1, CV_16S); // convert the image data to float type | |
namedWindow("CV_16S測試結果", 0); | |
imshow("CV_16S測試結果", t1); | |
t2.convertTo(t2, CV_16SC1); // convert the image data to unsigned short int | |
namedWindow("CV_16SC1測試結果", 0); | |
imshow("CV_16SC1測試結果", t2); | |
t3.convertTo(t3, CV_16SC2); // convert the image data to unsigned short int | |
namedWindow("CV_16SC2測試結果", 0); | |
imshow("CV_16SC2測試結果", t3); | |
t4.convertTo(t4, CV_16SC3); // convert the image data to unsigned short int | |
namedWindow("CV_16SC3測試結果", 0); | |
imshow("CV_16SC3測試結果", t4); | |
t5.convertTo(t5, CV_16SC4); // convert the image data to unsigned short int | |
namedWindow("CV_16SC4測試結果", 0); | |
imshow("CV_16SC4測試結果", t5); | |
/*=============================================================================*/ | |
//Signed 32bits | |
/*=============================================================================*/ | |
t6.convertTo(t6, CV_32F); // convert the image data to float type | |
namedWindow("CV_32F測試結果", 0); | |
imshow("CV_32F測試結果", t6); | |
t7.convertTo(t7, CV_32FC1); // convert the image data to float type | |
namedWindow("CV_32F測試結果", 0); | |
imshow("CV_32FC1測試結果", t7); | |
t8.convertTo(t8, CV_32FC2); // convert the image data to float type | |
namedWindow("CV_32F測試結果", 0); | |
imshow("CV_32FC2測試結果", t8); | |
t9.convertTo(t9, CV_32FC3); // convert the image data to float type | |
namedWindow("CV_32F測試結果", 0); | |
imshow("CV_32FC3測試結果", t9); | |
t10.convertTo(t10, CV_32FC4); // convert the image data to float type | |
namedWindow("CV_32F測試結果", 0); | |
imshow("CV_32FC4測試結果", t10); | |
/*=============================================================================*/ | |
waitKey(0); | |
//system("PAUSE"); | |
return 0; | |
} |
另外一些imread()函數內部搭配的參數
CV_LOAD_IMAGE_ANYCOLOR / 保持不變(原本圖像捨麼顏色就捨麼顏色)
src = imread("C:\\lena.jpg", 1);
src = imread("C:\\lena.jpg");
src = imread("C:\\lena.jpg", CV_LOAD_IMAGE_ANYCOLOR);
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include<opencv/cv.h> | |
#include<opencv/highgui.h> | |
using namespace cv; | |
/** 函式宣告 */ | |
int main() | |
{ | |
//CV_LOAD_IMAGE_ANYCOLOR | CV_LOAD_IMAGE_ANYDEPTH | |
Mat src,depthImage; | |
//depthImage = cv::imread("C:\\Users\\Mcu\\Desktoplena.jpg", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR); // Read the file | |
/*stage1*/ | |
src = imread("C:\\lena.jpg", CV_LOAD_IMAGE_ANYCOLOR); | |
namedWindow("stage1_lena剛載入", 0); | |
imshow("stage1_lena剛載入" , src); | |
waitKey(0); | |
//system("PAUSE"); | |
return 0; | |
} |
CV_LOAD_IMAGE_ANYDEPTH / 輸入圖像格式可以為8位無符號,16位無符號,32位有符號或者32位浮點型
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include<opencv/cv.h> | |
#include<opencv/highgui.h> | |
using namespace cv; | |
/** 函式宣告 */ | |
int main() | |
{ | |
//CV_LOAD_IMAGE_ANYCOLOR | CV_LOAD_IMAGE_ANYDEPTH | |
Mat src,depthImage; | |
//depthImage = cv::imread("C:\\Users\\Mcu\\Desktoplena.jpg", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR); // Read the file | |
/*stage1*/ | |
src = imread("C:\\lena.jpg",CV_LOAD_IMAGE_ANYDEPTH); | |
namedWindow("stage1_lena剛載入", 0); | |
imshow("stage1_lena剛載入" , src); | |
waitKey(0); | |
//system("PAUSE"); | |
return 0; | |
} |
CV_LOAD_IMAGE_COLOR // 彩色
CV_LOAD_IMAGE_GRAYSCALE// 灰階
=======================================================
<第二階段小測試>
void updateMotionHistory(InputArray silhouette,
InputOutputArray mhi,
double timestamp,
double duration )
Parameters:
- silhouette – Silhouette mask that has non-zero pixels where the motion occurs.
- mhi – Motion history image that is updated by the function (single-channel, 32-bit floating-point).
- timestamp – Current time in milliseconds or other units.
- duration – Maximal duration of the motion track in the same units as timestamp .
參考自
Motion Templates_updateMotionHistory
套用結果
最後是演算法部分整合效果
程式碼
#include "opencv2/video/tracking.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include <time.h> // for CLOCKS_PER_SEC 及 clock()
#include <stdio.h>
#include <ctype.h>
// various tracking parameters (in seconds)
const double MHI_DURATION = 3;//1s 為運動跟踪的最大持續時間
const double MAX_TIME_DELTA = 0.5;//最大時間增量為0.5s
const double MIN_TIME_DELTA = 0.05;//最小時間增量0.05s
// number of cyclic frame buffer used for motion detection
// (should, probably, depend on FPS)
const int N = 5;//frame buffer當中你要存取的frame數
// ring image buffer
IplImage **buf = 0; // 創建 frame buffer , 型態為IplImage * buf 的 Array
int last = 0;
// temporary images
IplImage *mhi = 0; // MHI
IplImage *orient = 0; // orientation
IplImage *mask = 0; // valid orientation mask
IplImage *segmask = NULL; // motion segmentation map
CvMemStorage* storage = NULL; // temporary storage
//用來建立一個指定大小的記憶體區塊,若為0,
//則建立的記憶體區塊大小依照預設值為64k
// parameters:
// img - input video frame
// dst - resultant motion picture
// args - optional parameters
static void update_mhi(IplImage* img, IplImage* dst, int diff_threshold)
{
double timestamp = (double)clock() / CLOCKS_PER_SEC; // 得到當前時間(以毫秒為單位)
//
CvSize size = cvSize(img->width, img->height); // //獲取目前攝像頭捕捉到的frame size
int i, idx1 , idx2;
IplImage* silh; //創建一個用來存輪廓(剪影)的圖像空間
CvSeq* seq; // 創建一序列
if (!mhi || mhi->width != size.width || mhi->height != size.height)
{
//如果frame的大小有所改變,就重新分配他們到緩衝區中
if (buf == 0) //如果IplImage *的陣列
{
buf = (IplImage**)malloc(N*sizeof(buf[0]));
memset(buf, 0, N*sizeof(buf[0]));
}
for (i = 0; i < N; i++) {
cvReleaseImage(&buf[i]);
buf[i] = cvCreateImage(size, IPL_DEPTH_8U, 1);
cvZero(buf[i]);
}
cvReleaseImage(&mhi);
cvReleaseImage(&orient);
cvReleaseImage(&segmask);
cvReleaseImage(&mask);
mhi = cvCreateImage(size, IPL_DEPTH_32F, 1);
cvZero(mhi); // clear MHI at the beginning
orient = cvCreateImage(size, IPL_DEPTH_32F, 1);
segmask = cvCreateImage(size, IPL_DEPTH_32F, 1);
mask = cvCreateImage(size, IPL_DEPTH_8U, 1);
}
cvCvtColor(img, buf[last], CV_BGR2GRAY); // convert frame to grayscale
//第一張 視訊影像在剛載入時先做了彩色轉灰階的功能
//並存放在frame buffer的IplImage *的指針(陣列中)
//buf[last] 即 buf[0] 第一個位置
//設定frame的索引編號
idx1 = last;
//將idx1設為編號0 (最近進來的視訊frame索引編號)
//執行第一輪 更新index到 0
//執行第二輪 更新index到 1
idx2 = (last + 1) % N;
// index of (last - (N-1))th frame
//idx2 代表 第 最新進來的視訊frame編號
//執行第一輪 更新index到 1
//執行第二輪 更新index到 2
last = idx2;//last以更新到index 1 之後
//執行第一輪 更新index到 1
//執行第二輪 更新index到 2
//做幀差(Frame Difference)
silh = buf[idx2];//silh首先會在此接收到來自緩衝區buf[1]的一張單通灰階影像
cvAbsDiff(buf[idx1], buf[idx2], silh);// get difference between frames
//執行第一輪 buffer 當中 index 0 - index 1 存給silh
//執行第二輪 buffer 當中 index 1 - index 2 存給silh
//對輪廓做二值化
cvThreshold(silh, silh, diff_threshold, 1, CV_THRESH_BINARY); // and threshold it
cvUpdateMotionHistory(silh, mhi, timestamp, MHI_DURATION); // update MHI
//第一個參數 silhouette : 由幀間差分(Frame difference)得到的運動輪廓圖像。
//第二個參數 mhi : motion histoty image的縮寫,表示運動歷史圖像。
//第三個參數 timestamp : 時間標記。
//第四個參數 duration : 發生過運動的像素所能保持的最長時間。
// convert MHI to 8u image(哪種通道混和效果由自己取決)
cvCvtScale(mhi, mask, 255. / MHI_DURATION,(MHI_DURATION - timestamp)*255. / MHI_DURATION);
cvZero(dst);//若預設通道合併處填為藍色就會在一開始顯示為藍色
//若我在此把cvZero(dst);註解掉你就會看到反色
//以藍色為例你看到的就會是黃背白前景
//這裡主要是設計用來將輪廓(剪影)以藍色通道來做顏色強弱顯示
cvMerge(mask, 0, 0, 0, dst); //合併單通道矩陣為成為多通道的圖形
//cvMerge(B,G,R,A,dst)
//前四個引數為單通道uchar型別的資料結構,
//第五個引數為輸出IplImage資料結構或CvMat結構圖形
// calculate motion gradient orientation and valid orientation mask
//計算運動歷史圖像的梯度方向
cvCalcMotionGradient(mhi, mask, orient, MAX_TIME_DELTA, MIN_TIME_DELTA, 3);
//cvCalcMotionGradient(mhi, mask, orient, MIN_TIME_DELTA, MAX_TIME_DELTA, 3);
//第一個參數 : 運動歷史圖像(單通道)
//第二個參數 : Mask 圖像;用來標註運動梯度數據正確的點,單通道8bits,為輸出參數
//第三個參數 : 運動梯度的方向圖像,包含從0 到360 角度
//第四個參數 : 函數在每個像素點(x,y) 鄰域尋找MHI 的最小值(m(x,y))
//第五個參數 : 函數在每個像素點(x,y) 鄰域尋找MHI 的最大值(m(x,y))
//min(delta1,delta2) <= M(x,y)-m(x,y) <= max(delta1,delta2)
//第六個參數 : Aperture size of sobel operator
//索貝爾運算子的光圈大小(函數所用微分算子的開孔尺寸CV_SCHARR, 1, 3, 5 or 7 (見cvSobel))
//Both inDelta1 and inDelta2 must be greater than 0.0 in cvCalcMotionGradient.
//History image must be REAL single-channel in cvCalcMotionGradient.
if (!storage)
storage = cvCreateMemStorage(0);//建立的記憶體區塊大小依照預設值為64k
else
cvClearMemStorage(storage);
// segment motion: get sequence of motion components
// segmask is marked motion components map. It is not used further
seq = cvSegmentMotion(mhi, segmask, storage, timestamp, MAX_TIME_DELTA);
//將整個運動分割為獨立的運動部分
//第一個參數 : 運動歷史圖像(單通道)
//第二個參數 : 發現應當存儲的mask圖像, 單通道32bits浮點數,用不同的單獨數字(1,2,...)標識它們
//第三個參數 : 包含運動連通域序列的內存存儲倉區塊
//第四個參數 :當前時間,以毫秒為單位
//第五個參數 : 分割閾值,推薦等於或大於運動歷史"每步"之間的間隔
}
int main(int argc, char** argv)
{
IplImage* motion = 0;
CvCapture* capture = 0;
capture = cvCaptureFromCAM(0); // 攝影機開啟
if (capture)
{
cvNamedWindow("Motion", 1);
for (;;)
{
IplImage* image = cvQueryFrame(capture);
if (!image)//判斷使否沒取到影格
break;
if (!motion)//如果motion圖像的資料結構為空值
{
motion = cvCreateImage(cvSize(image->width, image->height), 8, 3);
//就先產生3通道,大小跟攝影機捕捉到的影像相同的空間
//cvZero(motion);//設值為0---->
//若預設通道合併處填為藍色就會在一開始顯示為藍色
motion->origin = image->origin;
}
update_mhi(image, motion, 30);
//自定義的update_mhi函數(攝影機捕獲到的影像 , )
cvShowImage("Motion", motion);
if (cvWaitKey(10) >= 0)
break;
}
cvReleaseCapture(&capture);
cvDestroyWindow("Motion");
}
return 0;
}
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include<opencv/cv.h> | |
#include<opencv/highgui.h> | |
#include "opencv2/opencv.hpp" | |
#include <time.h> | |
#include <iostream> | |
using namespace cv; | |
using namespace std; | |
int main(int argc, char** argv) | |
{ | |
Mat frame,frame2, dst; | |
double timestamp = (double)clock() / CLOCKS_PER_SEC; // I found this in the Opencv/samples motempl.cpp | |
double duration = 15; //same as above , found this value in the opencv/samples/motempl.cpp | |
//double timestamp = clock(); | |
VideoCapture cap(0); | |
while (1) | |
{ | |
cap.read(frame); | |
cvtColor(frame, frame, CV_BGR2GRAY); | |
cap.read(dst); | |
cvtColor(dst, dst, CV_BGR2GRAY); | |
absdiff(frame, dst, frame2); | |
imshow("absolute frame difference", frame2); | |
threshold(frame2, frame2, 60, 255, THRESH_BINARY); | |
//Mat tst(frameHeight, frameWidth CV_32FC1); | |
//Mat.at(int y, int x) | |
Mat tst(frame2.rows, frame2.cols, CV_32FC1); | |
imshow("threshold", frame2); | |
updateMotionHistory(frame2, tst, timestamp , duration); | |
/* | |
void updateMotionHistory(InputArray silhouette, | |
InputOutputArray mhi, //single-channel, 32-bit floating-point | |
double timestamp, | |
double duration) | |
*/ | |
waitKey(30); | |
} | |
return 0; | |
} |
留言
張貼留言