📄 musicplay.cpp
字号:
/******************************************************************************
* 文件名:player.cpp
* 说明 :根据摄像头拍摄的人体动作来演奏音乐
* Modified by PRTsinghua@hotmail.com
******************************************************************************/
#include "stdafx.h"
#include "MusicPlay.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#include <windows.h>
#include <dshow.h>
#include <stdio.h>
#include <conio.h>
#include <qedit.h> // SampleGrabber用
#include <math.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <ctype.h>
#pragma comment(lib, "strmiids.lib")
#undef M_PI
#define M_PI 3.1415926535897932
#define HUGE
#define MAX_FILENAME_SIZE 128
#pragma comment(lib, "winmm.lib")
#define x_size 160
#define y_size 120
#define MAX_CNTR 10000
#define GRAY 128
#define PI 3.14159
// 图像结构
typedef struct{
HINSTANCE hi;
HWND hwnd; // 自己的窗口操作
BYTE *lpBmpData; // BMP数据
BITMAPINFOHEADER bih; // 位图信息
} IMG0;
// WAVE结构
typedef struct waveInst {
HANDLE hWaveInst;
HANDLE hWaveHdr;
HANDLE hWaveData;
} WAVEINST;
typedef WAVEINST FAR *LPWAVEINST;
// 全局变量和函数
int NumDevsOut;
WORD Version;
char szAppName[] = "oscillat"; // 应用名
HINSTANCE hInstApp = NULL; // 起动操作
HWND hwndApp = NULL; // 主要窗口的操作
HWND hwndChild[7] = {NULL}; // 文件名窗口的操作
HWAVEOUT hWaveOut = NULL;
LPWAVEHDR lpWaveHdr = NULL;
int tate;
int yoko;
int scale = 1;
long rec_freq = 44100L;
short rec_bits = 8;
long sec = 5;
char buf[256];
#define HANON (1.05946309435929526)
DWORD th_Proc0( void );
LRESULT CALLBACK grProc0( HWND, UINT, WPARAM, LPARAM );
DWORD th_Proc1( void );
LRESULT CALLBACK grProc1( HWND, UINT, WPARAM, LPARAM );
BOOL initVideo(void);
void closeVideo(void);
void initGraphic(void);
void closeGraphic(void);
void closeVideo(void);
void initWindow0(void);
void initWindow1(void);
void openWindow0(void);
void openWindow1(void);
void masuku(BYTE *);
int obtain_contour(int x_start, int y_start, unsigned char image[y_size][x_size]);
int remove_areas(BYTE *);
void haikei(BYTE *pRGB, BYTE *pRGB0, BYTE *pRGB1);
void HSV(double *H, double *S, double *V, double B, double G, double R);
int remove_areas2(void);
void cleanup(LPWAVEINST lpWaveInst);
void oscillatPlay(int, double);
void oscillatStop(void);
void makedata(DWORD dwDataSize, int pattern, double freq, unsigned char HUGE * lpData);
ICreateDevEnum *pDevEnum = NULL;
IGraphBuilder *pGraph = NULL;
IMediaControl *pMC = NULL;
ICaptureGraphBuilder2 *pCapture = NULL;
IBaseFilter *pF = NULL;
ISampleGrabber *pGrab = NULL; // 以上这些变量最后要释放
IMG0 img00, img01;
unsigned char image1[y_size][x_size];
unsigned char image3[y_size][x_size];
unsigned char line[x_size*y_size*3];
int chain_code[MAX_CNTR];
int Freeman[8][2] =
{
{1,0}, {1,-1}, {0,-1}, {-1,-1},
{-1,0}, {-1,1}, {0,1}, {1,1}
};
int ch_x[2];
int ch_y[2];
int check;
double Z;
int onkai = 0;
CWinApp theApp;
using namespace std;
// 主函数
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
// 初始化MFC
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
cerr << _T("Fatal Error: MFC initialization failed") << endl;
nRetCode = 1;
return nRetCode;
}
int X_SIZE, Y_SIZE;
BYTE *pRGB0, *pRGB1;
HRESULT hr;
initVideo(); // 视频的初期化
initGraphic(); // 图像画面的初期化
initWindow0(); // 视频画面表示的Window的初期化
initWindow1(); // 图像画面表示的Widow的初期化
printf( "图像输入开始,请按任意键\n" );
getch();
printf( "图像输入已经开始了,暂时停止 -- q\n" );
// ---- 图像输入开始 ----
// 制作表示窗口
openWindow0();
openWindow1();
pGrab -> SetBufferSamples(TRUE); // 开始grab
pMC -> Run(); // 开始rendering
// *********** 追加 ******************
BYTE *pRGB, *pRGB2;
Sleep(1000);
printf("记录初期背景图像,按任意键\n");
getch();
long n = img00.bih.biSizeImage;
pRGB = (BYTE *)malloc(n); // pRGB 初期背景图像的排列
pRGB2 = (BYTE *)malloc(n); // pRGB 初期背景图像的排列
if (pRGB == NULL)
{
printf("内存不足(pRGB)\n");
}
hr = pGrab -> GetCurrentBuffer( &n, (long *)pRGB );
// ********** 到这里为止 ******************
while(1)
{
long n = img00.bih.biSizeImage;
hr = pGrab -> GetCurrentBuffer( &n, (long *)img00.lpBmpData );
pRGB0 = img00.lpBmpData;
pRGB1 = img01.lpBmpData;
X_SIZE = img00.bih.biWidth;
Y_SIZE = img00.bih.biHeight;
// pRGB0 视频图像的图像排列
// pRGB1 进行图像处理后的图像的排列
// 数据的格式,沿着从下到上的方向。
// 按BGR的顺序排列
haikei(pRGB, pRGB0, pRGB1);
masuku(pRGB1);
remove_areas(pRGB1);
InvalidateRect( img00.hwnd, NULL, FALSE); // 输入画像窗口的更新
InvalidateRect( img01.hwnd, NULL, FALSE); // 画像窗口的更新
if( kbhit() )
{
getch();
hr = pMC -> Pause();
printf("grab停止:结束 - q 、再次打开 - 别的键\n");
if(getch() == 'q')
break;
pMC -> Run();
}
}
pMC -> Stop();
pGrab -> SetBufferSamples( 0 );
// ---- 结束操作 ----
oscillatStop();
closeVideo();
closeGraphic();
SendMessage( img00.hwnd, WM_CLOSE, 0, 0 ); // 图像输入窗口结束
SendMessage( img01.hwnd, WM_CLOSE, 0, 0 ); // 图像表示窗口结束
return 0;
}
/******************************************************************************
* 源图像窗口的创建与消息循环
******************************************************************************/
DWORD th_Proc0( void )
{
MSG msg;
int sm0 = GetSystemMetrics( SM_CYCAPTION );
int sm1 = GetSystemMetrics( SM_CXDLGFRAME ); // WS_OVRELAPP的时候,框子的宽度
int sm2 = GetSystemMetrics( SM_CYDLGFRAME ); // 变成了SM_CYDLGFRAME
// 创建窗口
img00.hwnd = CreateWindow( "GRC0", // 组的名字
"Source Image",
WS_OVERLAPPED | WS_VISIBLE, // 窗口的属性
0, 100, // 表示的位置
img00.bih.biWidth + sm1 * 2, // 描绘大小,计算大小
img00.bih.biHeight + sm0 + sm2 * 2,
HWND_DESKTOP,
NULL, img00.hi, NULL );
while( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return 0;
}
/******************************************************************************
* 处理后图像窗口的创建与消息循环
******************************************************************************/
DWORD th_Proc1( void )
{
MSG msg;
int sm0 = GetSystemMetrics( SM_CYCAPTION );
int sm1 = GetSystemMetrics( SM_CXDLGFRAME ); // WS_OVRELAPP的时候,框子的宽度
int sm2 = GetSystemMetrics( SM_CYDLGFRAME ); // 变成了SM_CYDLGFRAME
// 创建窗口
img01.hwnd = CreateWindow( "GRC1", // 小组的名字
"Result Image",
WS_OVERLAPPED | WS_VISIBLE, // 窗口的属性
0, 400, // 表示的位置
img01.bih.biWidth + sm1 * 2, // 描绘大小 计算大小
img01.bih.biHeight + sm0 + sm2 * 2,
HWND_DESKTOP,
NULL, img01.hi, NULL );
while( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return 0;
}
/******************************************************************************
* 窗口的取得,仅仅在再一次的描绘中进行
******************************************************************************/
LRESULT CALLBACK grProc0( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
PAINTSTRUCT ps;
switch (msg)
{
case WM_PAINT: // 描绘位图
BeginPaint( hwnd, &ps );
SetDIBitsToDevice( ps.hdc, 0, 0, // 复制刚才x,y的坐标
img00.bih.biWidth, // DIB的宽度
img00.bih.biHeight, // DIB的高度
0, 0, // DIB的坐标
0, // 扫描线
img00.bih.biHeight, // 扫描线的数量
img00.lpBmpData,
(BITMAPINFO *)&( img00.bih), // 分派到BITMAPINFO
DIB_RGB_COLORS );
EndPaint( hwnd, &ps );
return 0;
case WM_DESTROY:
PostQuitMessage( 0 ); // 结束信息循环
break;
default:
return DefWindowProc( hwnd, msg, wp, lp );
}
return 0;
}
/******************************************************************************
* 窗口的取得,仅仅在再一次的描绘中进行
******************************************************************************/
LRESULT CALLBACK grProc1( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
PAINTSTRUCT ps;
switch (msg)
{
case WM_PAINT: // 描绘位图
BeginPaint( hwnd, &ps );
SetDIBitsToDevice( ps.hdc, 0, 0, // 复制刚才x,y的坐标
img01.bih.biWidth, // DIB的宽度
img01.bih.biHeight, // DIB的高度
0, 0, // DIB的坐标
0, // 扫描线
img01.bih.biHeight, // 扫描线的数量
img01.lpBmpData,
(BITMAPINFO *)&( img01.bih), // 分派到BITMAPINFO
DIB_RGB_COLORS );
EndPaint( hwnd, &ps );
return 0;
case WM_DESTROY:
PostQuitMessage( 0 ); // 结束信息循环
break;
default:
return DefWindowProc( hwnd, msg, wp, lp );
}
return 0;
}
/******************************************************************************
* 初始化Video
******************************************************************************/
BOOL initVideo(void)
{
AM_MEDIA_TYPE amt;
CoInitialize(NULL); // COM的初期化
// ---- 输入计算的准备 ----
// 搜索输入设备
IBaseFilter *pbf = NULL;
IMoniker * pMoniker = NULL;
ULONG cFetched;
// 创建输入设备的各个部分
CoCreateInstance( CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
IID_ICreateDevEnum, (void ** ) &pDevEnum);
// 设置视频输入设备的各个部分
IEnumMoniker * pClassEnum = NULL;
pDevEnum -> CreateClassEnumerator(
CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
if (pClassEnum == NULL)
{
AfxMessageBox("没有发现摄像头,程序将退出!");
pDevEnum -> Release();
CoUninitialize();
return FALSE ;
}
// 取得最初发现的视频输入设备object的接口
pClassEnum -> Next(1, &pMoniker, &cFetched);
pMoniker->BindToObject( 0, 0, IID_IBaseFilter, (void**)&pbf );
// ---- 过虑图像的准备 ----
// 创建过虑图像,取得接口
CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC,
IID_IGraphBuilder, (void **) &pGraph);
pGraph -> QueryInterface( IID_IMediaControl, (LPVOID *) &pMC );
// 把输入图像追加到过虑图像
pGraph -> AddFilter( pbf, L"Video Capture");
// 因为进行了追加所以解除参照的输入图像
pbf -> Release();
// ---- 过虑图像的准备 ----
// 创建过虑图像,取得接口
CoCreateInstance( CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (LPVOID *)&pF);
pF -> QueryInterface( IID_ISampleGrabber, (void **)&pGrab );
// 把输入图像追加到过虑图像
ZeroMemory(&amt, sizeof(AM_MEDIA_TYPE));
amt.majortype = MEDIATYPE_Video;
amt.subtype = MEDIASUBTYPE_RGB24;
amt.formattype = FORMAT_VideoInfo;
pGrab -> SetMediaType( &amt );
// 把grubber过虑追加到过虑图像
pGraph -> AddFilter(pF, L"SamGra");
// ---- 输入图像的准备 ----
// 创建输入图像
CoCreateInstance( CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,
IID_ICaptureGraphBuilder2, (void **) &pCapture );
// 把过虑图像编入到输入图像
pCapture -> SetFiltergraph( pGraph );
// 输入图像的设定,设定grubber为rendering输出
pCapture -> RenderStream (&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
pbf, NULL, pF);
// ---- 表示窗口的准备 ----
// 位图信息的取得
pGrab -> GetConnectedMediaType( &amt );
// 获得视频头部的信息
VIDEOINFOHEADER *pVideoHeader = (VIDEOINFOHEADER*)amt.pbFormat;
// 在视频的头部包含位图的信息
// 把位图的信息复制到BITMAPINFO的结构体中
BITMAPINFO BitmapInfo;
ZeroMemory( &BitmapInfo, sizeof(BitmapInfo) );
CopyMemory( &BitmapInfo.bmiHeader, &(pVideoHeader->bmiHeader),
sizeof(BITMAPINFOHEADER));
img00.bih = BitmapInfo.bmiHeader;
long n = img00.bih.biSizeImage;
char s[100];
sprintf(s, "Video Width: %ld Video Height: %ld",
img00.bih.biWidth, img00.bih.biHeight);
AfxMessageBox(s);
img00.lpBmpData = (BYTE *)malloc( n );
// ************* 追加 *****************
if (img00.lpBmpData == NULL) {
AfxMessageBox("内存不足!");
}
img00.hi = (HINSTANCE)GetWindowLong( HWND_DESKTOP, GWL_HINSTANCE );
return true;
}
/******************************************************************************
* 初始化Graphics
******************************************************************************/
void initGraphic(void)
{
// 把位图的信息复制到BITMAPINFO的结构体中
BITMAPINFO BitmapInfo;
ZeroMemory( &BitmapInfo, sizeof(BitmapInfo) );
CopyMemory( &BitmapInfo.bmiHeader, &img00.bih,
sizeof(BITMAPINFOHEADER));
img01.bih = BitmapInfo.bmiHeader;
long n = img01.bih.biSizeImage;
img01.lpBmpData = (BYTE *)malloc( n );
// **************** 追加 ******************
if (img01.lpBmpData == NULL) {
printf("内存不足 (img01.lpBmpData)\n");
}
img01.hi = (HINSTANCE)GetWindowLong( HWND_DESKTOP, GWL_HINSTANCE );
}
/******************************************************************************
* 关闭Video
******************************************************************************/
void closeVideo(void)
{
// 接口的解除
pMC -> Release();
pDevEnum -> Release();
pGraph -> Release();
pCapture -> Release();
CoUninitialize();
free( img00.lpBmpData );
}
/******************************************************************************
* 关闭Graphic
******************************************************************************/
void closeGraphic(void)
{
free( img01.lpBmpData );
}
/******************************************************************************
* 初始化窗口0
******************************************************************************/
void initWindow0(void)
{
// 表示窗口的定义
WNDCLASSEX wc; // 新做成的窗口组
memset( &wc, 0, sizeof(WNDCLASSEX) );
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = grProc0; // 取得持有这个组的窗口
wc.hInstance = (HINSTANCE)GetWindowLong( HWND_DESKTOP, GWL_HINSTANCE );
wc.lpszClassName = "GRC0"; // 这个组的名字
wc.cbWndExtra = 10; // 确保相关的结构体的特点的范围
RegisterClassEx( &wc ); // 窗口组的登记
}
/******************************************************************************
* 初始化窗口1
******************************************************************************/
void initWindow1(void)
{
// 表示窗口的定义
WNDCLASSEX wc; // 新做成的窗口组
memset( &wc, 0, sizeof(WNDCLASSEX) );
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = grProc1; // 取得持有这个组的窗口
wc.hInstance = (HINSTANCE)GetWindowLong( HWND_DESKTOP, GWL_HINSTANCE );
wc.lpszClassName = "GRC1"; // 这个组的名字
wc.cbWndExtra = 10; // 确保相关的结构体的特点的范围
RegisterClassEx( &wc ); // 窗口组的登记
}
/******************************************************************************
* 打开窗口0
******************************************************************************/
void openWindow0(void)
{
DWORD tid;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -