OpenCV 的cvCircle函数

写了一个小程序,获得摄像头输出之后直接在上面画图。

cvCircle(CvArr* img, CvPoint center, int radius, CvScalar color, int thickness=1, int lineType=8, int shift=0)

img为图像指针,单通道多通道都行,不需要特殊要求
center为画圆的圆心坐标
radius为圆的半径
color为设定圆的颜色,比如用CV_RGB(255, 0,0)设置为红色

thickness为设置圆线条的粗细,值越大则线条越粗,为负数则是填充效果 【参考1】

#include "stdafx.h"
#include "highgui.h"
#include "cv.h"
#include "stdio.h"
#include <ctype.h>
 
int main(int argc,char ** argv)
{
		int	r=0;

       CvCapture *capture = 0;

	   //从摄像头读取
       capture = cvCaptureFromCAM(0);

 
       if(!capture)
       {
              fprintf(stderr,"Could not initialize capturing...\n");
              return -1;
       }
 
       cvNamedWindow("Laplacian",1);
 
       //循环捕捉,直到用户按键跳出循环体
       for(;;)
       {
              IplImage * frame =0;
             
              //抓起一祯
              frame = cvQueryFrame(capture);
 
              if(!frame)
                     break;

			  r>20?r=0:r++;


			  //画一个圈  
			  cvCircle(frame,cvPoint(frame->width / 2,frame->height /2 ), 45+abs(10-r), CV_RGB(150, 100,100), 4, 8, 0);

              cvShowImage("Laplacian",frame);
 
              if(cvWaitKey(10)>0)
                     break;
       }
       cvReleaseCapture(&capture);
       cvDestroyWindow("Laplacian");
       return 0;
}

 

campaint

参考:
1.http://blog.163.com/yuhua_kui/blog/static/9679964420141104385570/ OpenCV cvCircle函数
2.http://wiki.opencv.org.cn/index.php/Cxcore%E7%BB%98%E5%9B%BE%E5%87%BD%E6%95%B0 Cxcore绘图函数

如何在XP上部署OpenCV编写的程序

本文使用环境:

1. XP 下,VS2008
2. 只适合你用Release编译出来的结果,不适合Debug版本(因为我测试Debug版本在XP上始终无法成功,所以删除了所有相关的 *d.dll)
3. 只是简单的测试之类的(如果你想更专业,可以只分发用到的DLL;或者重新编译OpenCV生成 Lib,通过静态编译将内容添加到你的EXE中)

步骤:

1.按照Debug编译,然后在工作机上测试OK
2.将生成的 Release 目录下的全部内容拷贝到dll的目录下 OpenCVXPPackage
3.如果目标机之前没有安装过 VS2008 的支持包,需要先安装一次vcredist2008sp1
4.之后在目标机上运行生成的 EXE 即可

注意:
如果出现 “应用程序正常初始化(0xc0000135)失败。请单击‘确定’,终止应用程序”,请安装 Microsoft .NET Framework 2.0

vcredist2008sp1:
vcredist2008sp1

OpenCVXPPackage(其中包含了一个编译好的测试应用程序):
OpenCVXPPackage

应用程序运行结果:
Capture

带有自动提示功能的手机座

起因:有网友抱怨,因为陪着孩子在家玩,漏接了公司的重要电话,被罚款500(如果真的是人民币的话,我相信他一定乐于看到这个产品)

看到这个需求,我忽然想是否可以用 Arduino来打造一个能够提醒的盒子呢? 当然,解决方法还有很多,严小姐听了我的目标之后第一个反应是为什么不换一个山寨机,大屏幕啊有没有,超长待机啊有没有,八个喇叭啊有没有,只要499啊有没有。我回答有很多人喜欢老物件有感情而已。她又在问为什么,终于被我意味深长的眼神说服了。

下面就开始动手实做了。从触发的角度来说最稳妥的办法还是安装APP,Android和iOS都是可行的,只是…….默默的轻抚了一下自己的 Nokia E72,放弃了这个方案。翻翻元件箱,里面有振动开关,那就凑合着用吧。提示方面,最近入手了一个具有录音放音功能的模块ISD1820,使用非常简单,GPIO足以搞定(多说一句,上面有麦克风和一个录音按钮,按下这个按钮对着它高歌一曲即记录在芯片中。时间比较短,只能记录10秒)。选用了 8×8 LED模块作为提示灯光,它在之前的《电子骰子系列》登场过。

原理上很简单,就是检测连续振动确定是振铃–>触发装置,每隔10秒提示一次–>如果有人按下Stop按钮就停止提示。

用到的配件

IMG_2553

用面包板来验证电路

IMG_2502

 

侧面有一个喇叭,一个按钮

IMG_2517

 

正面俯视,有一个 8×8点阵

 

IMG_2518

 

振动传感器

IMG_2550

 

内部线路看起来有点复杂

IMG_2551

 

另外一边做出一个洞,给 Arduino供电

 

IMG_2516

 

#include "LedControl.h"

const int ShockTestPin = 4; //Pin for vibration sensor
const int AlartPin = 5;     //LED Alert
const int StopPin = 6;      //Stop button
int sta=0;

//pin 12 is connected to the DataIn
//pin 11 is connected to the CLK
//pin 10 is connected to LOAD
//We have only a single MAX72XX.
LedControl lc=LedControl(12,11,10,1);

void showface() {
/* here is the data for the characters */
byte face[8]={
B00000100,
B00100010,
B01000110,
B01000000,
B01000000,
B01000110,
B00100010,
B00000100};

lc.setRow(0,0,face[0]);
lc.setRow(0,1,face[1]);
lc.setRow(0,2,face[2]);
lc.setRow(0,3,face[3]);
lc.setRow(0,4,face[4]);
lc.setRow(0,5,face[5]);
lc.setRow(0,6,face[6]);
lc.setRow(0,7,face[7]);

}

void setup() {

  Serial.begin(9600);

  pinMode(ShockTestPin, INPUT);   
  pinMode(AlartPin,OUTPUT);
  digitalWrite(AlartPin,LOW),
  pinMode(StopPin,INPUT);  //Stop pin for input

  //The MAX72XX is in power-saving mode on startup,
  //we have to do a wakeup call

  lc.shutdown(0,false);
  //Set the brightness to a medium values
  lc.setIntensity(0,8);
  //and clear the display
  lc.clearDisplay(0);

} // End of Setup

void loop() {
 long int start;
  
  if (0==sta) {       //Status One: Test status
     boolean shock=false;
     
     start=millis();
     while (millis()-start<=1000L) { //Test vibration for 1 second 
        if (LOW==digitalRead(ShockTestPin)) {  //If there is virbration signal
          shock=true;                          //Mark true
          break;
        } //if (LOW==digitalRead(ShockTestPin))
     }   
     if (false==shock) {sta=0; goto Sta1End;}    //If in the one seconds there is no vibration, it should break
     delay(500);
     
     start=millis();
     while (millis()-start<=1000L) { //Test vibration for 1 second 
        if (LOW==digitalRead(ShockTestPin)) {  //If there is virbration signal
          shock=true;                          //Mark true
          break;
        } //if (LOW==digitalRead(ShockTestPin))
     }   
     if (false==shock) {sta=0; goto Sta1End;}    //If in the one seconds there is no vibration, it should break
     delay(500);

     start=millis();
     while (millis()-start<=1000L) { //Test vibration for 1 second 
        if (LOW==digitalRead(ShockTestPin)) {  //If there is virbration signal
          shock=true;                          //Mark true
          break;
        } //if (LOW==digitalRead(ShockTestPin))
     }   
     if (false==shock) {sta=0; goto Sta1End;}    //If in the one seconds there is no vibration, it should break
     delay(500);
    
     //It means we have test vibration in 3 seconds 
     sta=1;
  Sta1End:
      ;  
  }
  
  if (1==sta) {
      //Play the voice that we have record
      digitalWrite(AlartPin,LOW);
      digitalWrite(AlartPin,HIGH);
      delay(100);
      digitalWrite(AlartPin,LOW);
      
      //Delay 10 seconds
      start=millis();
     
      while (millis()-start<=15000L)
      {
        if (LOW==digitalRead(StopPin)) { //We will stop the playing ,if we test the stop button is pressed
          sta=0;
          lc.clearDisplay(0);   
          break;
        }
        if (0==(millis()-start)/1000L % 2) {
           showface(); 
        }
       else
        {
            lc.clearDisplay(0);          
        } 
      }//while (millis()-start<=15000L)

  }//if (1==sta)
}

 

具体的使用方法拍了一个简单的视频,本人倾力献

最后放两张靓照

IMG_2544

IMG_2547

这只是很粗糙的原型,如果真想做出来实用的还有很长的路要走。比如:让检测更灵敏更可靠,或者干脆使用手机的声音作为触发条件。提示音量再大一些。或者再加上充电功能就更加实用,也给需要一直插着让Arduino供电找到更好的借口。

然后严小姐的问题是:如果忽然有很强的振动,误触发了怎么办,如果家里确实没有人它又一直在叫怎么办,如果隔壁在装修,有振动有噪音怎么办?好吧,如果你肯再品准500+以上的预算,让我买块蓝牙开发板,我相信一定不是问题。哦,对了还要换一个支持Android的手机才好啊。

VS2008 + hidsdi.h 的问题

目标:编写一个枚举系统中所有USB HID设备的程序。在编写过程中遇到编译链接无法通过的情况,尝试各种方法都不成功。 Google上不去,Baidu的方法基本上都尝试了一遍,产生问题的原因大约是 DDK(3790.1830 算是比较老的版本)中的库和VS2008(Express版本)有冲突。最后琢磨了一下,不妨直接将用到的 Lib 和函数(这个例子只用了一个HidD_GetHidGuid,在 hidsdi.h 中定义),直接放到程序中。结果居然很好用~

#include "stdafx.h"
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <setupapi.h>
extern "C" {
void __stdcall
HidD_GetHidGuid (
   OUT   LPGUID   HidGuid
   );
typedef struct _HIDD_ATTRIBUTES {
    ULONG   Size; // = sizeof (struct _HIDD_ATTRIBUTES)

    //
    // Vendor ids of this hid device
    //
    USHORT  VendorID;
    USHORT  ProductID;
    USHORT  VersionNumber;

    //
    // Additional fields will be added to the end of this structure.
    //
} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;

BOOLEAN __stdcall
HidD_GetAttributes (
    IN  HANDLE              HidDeviceObject,
    OUT PHIDD_ATTRIBUTES    Attributes
    );
}

#pragma comment( lib, "hid.lib" )
#pragma comment( lib, "setupapi.lib" )

#define ShowError() ShowError_(_T(__FILE__),__LINE__)

void ShowError_(LPCTSTR file, long line)
{
    LPVOID lpMsgBuf;
    FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS
        , NULL, GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, NULL );
    _tprintf( _T("---ERROR %s(%ld): %s\n"), file, line, (LPCTSTR)lpMsgBuf );
    LocalFree( lpMsgBuf );
}

int main(array<System::String ^> ^args)
{
	 GUID HidGuid;

	//获取HID设备的接口类GUDI
		HidD_GetHidGuid(&HidGuid);
	//输出一下看看GUID
		printf("HID GUID: {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n"
		   , HidGuid.Data1, HidGuid.Data2, HidGuid.Data3
		   , HidGuid.Data4[0], HidGuid.Data4[1], HidGuid.Data4[2], HidGuid.Data4[3], HidGuid.Data4[4]
		   , HidGuid.Data4[5], HidGuid.Data4[6], HidGuid.Data4[7] );
	
	//根据获得的GUID枚举HID设备
	HDEVINFO hDevInfo = SetupDiGetClassDevs( &HidGuid, NULL, 0, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE );
    if( INVALID_HANDLE_VALUE != hDevInfo )
    {
        SP_DEVICE_INTERFACE_DATA strtInterfaceData = { sizeof(SP_DEVICE_INTERFACE_DATA) };
        for( DWORD index=0; SetupDiEnumDeviceInterfaces(hDevInfo,NULL,&HidGuid,index,&strtInterfaceData); ++index )
        {
            char buf[1000];
            SP_DEVICE_INTERFACE_DETAIL_DATA& strtDetailData = (SP_DEVICE_INTERFACE_DETAIL_DATA&)buf[0];
            strtDetailData.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
            if( SetupDiGetDeviceInterfaceDetail(hDevInfo,&strtInterfaceData,&strtDetailData,_countof(buf),NULL,NULL) )
            {
                _tprintf( _T("[%d] path: %s\n"), index, strtDetailData.DevicePath );

                HANDLE hUsb = CreateFile( strtDetailData.DevicePath, 0//GENERIC_READ|GENERIC_WRITE
                    , FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
                if( INVALID_HANDLE_VALUE != hUsb )
                {
                    // 查询设备标识
                    HIDD_ATTRIBUTES strtAttrib = { sizeof(HIDD_ATTRIBUTES) };
                    if( HidD_GetAttributes(hUsb,&strtAttrib) )
                    {
                        _tprintf( _T("VendorID : %hX\n"), strtAttrib.VendorID );
                        _tprintf( _T("ProductID: %hX\n"), strtAttrib.ProductID );
                        _tprintf( _T("VerNumber: %hX\n"), strtAttrib.VersionNumber );
                    }
                    else
                        ShowError();

                    CloseHandle( hUsb );
                }
                else
                    ShowError();
            }
            else
                ShowError();
        }
        if( GetLastError() != ERROR_NO_MORE_ITEMS )
            ShowError();

        SetupDiDestroyDeviceInfoList( hDevInfo );
    }
    else
        ShowError();

	system("PAUSE");
    return 0;
}

 

下载 HidTest

参考:

1.http://blog.csdn.net/xuxinhua/article/details/6329182 转: vs2008 hidsdi.h 问题

Step to UEFI (12) —- EADK 中的 Time 函数

这次的工作是基于 EADK 的,编译借用EADK的环境这样做有编译速度快,测试方便的优点,具体配置请参考 ”http://www.lab-z.com/how-to-use-eadk/“

关于 time_t 的定义可以在 \EadkPkg_A2\StdLib\Include\time.h 中看到。测试了一下,sizeof(time_t) == 4。

time()函数取得的结果是当前系统的时间,具体的定义是:返回从GMT1970年1月1日 0:0:0 开始经过的秒数表示的当前时间和日期。

下面可以看到 time() 有两种用法。

代码如下,很简单

/** @file
    A simple, basic, application showing how the Hello application could be
    built using the "Standard C Libraries" from StdLib.

    Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
    This program and the accompanying materials
    are licensed and made available under the terms and conditions of the BSD License
    which accompanies this distribution. The full text of the license may be found at
    http://opensource.org/licenses/bsd-license.

    THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
    WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
//#include  <Uefi.h>
//#include  <Library/UefiLib.h>
//#include  <Library/ShellCEntryLib.h>

#include  <stdio.h>
#include  <time.h>

/***
  Demonstrates basic workings of the main() function by displaying a
  welcoming message.

  Note that the UEFI command line is composed of 16-bit UCS2 wide characters.
  The easiest way to access the command line parameters is to cast Argv as:
      wchar_t **wArgv = (wchar_t **)Argv;

  @param[in]  Argc    Number of argument tokens pointed to by Argv.
  @param[in]  Argv    Array of Argc pointers to command line tokens.

  @retval  0         The application exited normally.
  @retval  Other     An error occurred.
***/
int
EFIAPI
main (
  IN int Argc,
  IN char **Argv
  )
{

  time_t t;

  time(&t);

  printf("%ld\n",t);

  t=time(NULL);

  printf("%s\n",ctime(&t));

  return 0;
}

 

运行结果

time

下载

main

参考:

1.http://ganquan.info/standard-c/function/time Standard C 语言标准函数库速查 (Cheat Sheet)

2.书籍 《C函数实用手册》 个人感觉这本书不错,蛮实用,实例详尽。缺点是缺少一些新的C函数,可能是因为这本书目标是TC,并且是2003年的书籍。当初是为了用 Turbo C 所以才买的.

Arduino制作一个电子骰子(3)

上面几篇文章介绍的都是虚拟的电子骰子,这篇文章将会介绍用Arduino来玩实体的骰子。相比前面几篇材料更复杂,牵涉到的配备更多。当然,所有的技术问题都能找到合理的解释,暂时无法回答的问题是“这个东西能干什么?”

首先介绍使用到的材料:

1. 电动骰子机(toabao购买,电池驱动,上面有个按钮,按动时自动旋转骰子)
2. 继电器 (我们用它来控制上面骰子机的开关)
3. 电池夹(用来给骰子机供电)
4. Arduino UNO (最基础的型号足够用的,如果你有其他的型号肯定也没问题)
5. 摄像头 (我选用的是 罗技的 U-VQN42,这是很老的型号,以至于目前没有Win7的驱动)
6. 电脑 (我们用摄像头采集图像,然后使用Intel 的OpenCV来进行图像的识别处理)

可以看出这个实验涉及到的内容远远比之前的复杂,设计这个实验大约花费了2周左右,实做将近两天。

从流程上来说,功能过程如下:

Drawing1

硬件部分的介绍:
介绍Arduino的连接:

Untitled Sketch_bb

虽然骰子机内部是要安装2节电池的,但是我发现我用一节五号充电电池也能让它工作的很好,考虑到外壳强度的问题,也就直接选择一节电池了。Arduino在这里就是发挥骰子机开关的功能。

此外的建议是:连接继电器的常断开端口,这样,当断电时骰子机不会转动。

image003

骰子机原来的是亚克力外壳,因为反光的问题,在测试时结果不理想,所以重新用纸做了一个。这里特别感谢严小姐,她用灵巧的双手帮我完成了这个工作。可以看到,目前整个摄像头可以伸进去,视界中只有地盘和白色的区域,这对于识别是非常有利的。还建议使用一个外部固定光源来进行补光之类的设定。

image004

软件部分:

1. Arduino程序。

#define LED_PIN 13

void setup()
{
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
//Default
digitalWrite(LED_PIN, HIGH);
}

void loop()
{
char c;

while (Serial.available() > 0)
{
c=Serial.read();
if (‘b’==c)
{
digitalWrite(LED_PIN, LOW);
}
if (‘s’==c)
{
digitalWrite(LED_PIN, HIGH);
}
}
}

实验中 Arduino 的程序非常简单,测试时可以使用 Putty 这样的工具打开对应串口,直接发送命令测试。

2. PC端程序。

因为要使用OpenCV,所以选择了VS2008,本打算使用Delphi,无奈他的OpenCV不成熟。

这个程序可能分成两部分,一部分是串口通讯,只需要发送部分【参考1】,另外一部分是OpenCV的识别。算法上来自【参考2】,他给出了一种非常简单的算法:首先对图像进行Canny边缘提取,然后使用FloodFill对于包络范围进行填充,同时会返回填充区域的面积,利用面积就可以判断识别出来的是否为骰子的点(例如:1点的时候面积可能在200左右,2点的话,每个点可能在50左右),对于处在合理面积中的识别区域就判断为点数。

#include “stdafx.h”
#include <opencv2/opencv.hpp>
#include <opencv/cv.h>
#include <opencv/cxcore.h>
#include “opencv2/highgui/highgui.hpp”
#include

using namespace cv;

int p1=49, p2=258; //Paramters for Canny
Mat framepic; //framepic 存放摄像头抓取图像
Mat framegray; // framepic 灰度化后的图像
Mat canny; //canny 存放摄像头处理后的图像
VideoCapture cap(0);
int count[7]={0,0,0,0,0,0,0};
int counter=0;
int retry=0;

void on_trackbar(int, void*) {
Canny(framegray, canny, p1, p2);
imshow(“canny”, canny);
}

void delayshow(int dSecond){
time_t sTime=time(NULL);

while (difftime(time(NULL),sTime)<dSecond)
{
cap>>framepic;
cvtColor(framepic,framegray, CV_BGR2GRAY);
GaussianBlur(framegray, framegray,Size(7,7),1.5,1.5);
Canny(framegray, canny, p1, p2);
imshow(“canny”, framegray);
imshow(“Preview”,canny);
int c=waitKey(33);
if(c==27) break;
}
}

int main(int argc, const char** argv)
{
//==============================================
//code for COM port communication Begin
//==============================================
DCB dcb;
HANDLE hCom;
BOOL fSuccess;
TCHAR SPort[]=L”\\\\.\\COM7″;

char txcharstart[]=”b”; //b char for Start shaking dice
char txcharstop []=”s”; //s char for Stop shaking dice

DWORD iBytesWritten;

//Prepare COM part communication
hCom = CreateFile(SPort,
GENERIC_WRITE,
0, // must be opened with exclusive-access
NULL, // no security attributes
OPEN_EXISTING, // must use OPEN_EXISTING
0, // not overlapped I/O
NULL // hTemplate must be NULL for comm devices
);

if (hCom == INVALID_HANDLE_VALUE)
{
// Handle the error.
printf (“[Error] CreateFile failed with error %d.\n”, GetLastError());
return (1);
}

SetupComm(hCom, 32, 32);

// Build on the current configuration, and skip setting the size
// of the input and output buffers with SetupComm.

fSuccess = GetCommState(hCom, &dcb);

if (!fSuccess)
{
// Handle the error.
printf (“[Error] GetCommState failed with error %d.\n”, GetLastError());
return (2);
}

// Fill in DCB: 9600 bps, 8 data bits, no parity, and 1 stop bit.

dcb.BaudRate = CBR_9600; // set the baud rate
dcb.ByteSize = 8; // data size, xmit, and rcv
dcb.Parity = NOPARITY; // no parity bit
dcb.StopBits = ONESTOPBIT; // one stop bit

fSuccess = SetCommState(hCom, &dcb);

if (!fSuccess)
{
// Handle the error.
printf (“[Errror] SetCommState failed with error %d.\n”, GetLastError());
return (3);
}
//==============================================
//code for COM port communication End
//==============================================

srand(time(NULL));

int dTime;
if(!cap.isOpened())
return -1;

cap>>framepic;
cvtColor(framepic,framegray, CV_BGR2GRAY);
Canny(framegray, canny, p1, p2);
imshow(“canny”, framegray);
imshow(“Preview”, framegray);

//You may have to find the P1 and P2 value for your environment
createTrackbar(“p1″,”canny”,&p1,1000,on_trackbar);
createTrackbar(“p2″,”canny”,&p2,1000,on_trackbar);

//Loop shaking dice and count
for(;;)
{
//Shake start
printf (“[Message] Send start command \n”);
if (FALSE==WriteFile(hCom, &txcharstart, strlen(txcharstart), &iBytesWritten,NULL)) {
printf(“[Error]: %d”, GetLastError());
retry=0;
while ((TRUE==WriteFile(hCom, &txcharstart, strlen(txcharstart), &iBytesWritten,NULL)) ||
(retry>5))
{
printf(“[Error]: %d”, GetLastError());
retry++;
}
}

dTime=rand()%2+1;

//Shake the dice for a random seconds
printf(“Shake delay %d \n”,dTime);
delayshow(dTime);

//Shake stop
printf (“[Message] Send stop command \n”);
if (FALSE==WriteFile(hCom, &txcharstop, strlen(txcharstop), &iBytesWritten,NULL)) {
printf(“[Error]: %d”, GetLastError());
retry=0;
while ((TRUE==WriteFile(hCom, &txcharstop, strlen(txcharstop), &iBytesWritten,NULL)) ||
(retry>5))
{
printf(“[Error]: %d”, GetLastError());
retry++;
}
}

//It delay 5 seconds for dice stopping
delayshow(5);

//==============================================
//code dice point recognize start
//==============================================
cap>>framepic;
cvtColor(framepic,framegray, CV_BGR2GRAY);
GaussianBlur(framegray, framegray,Size(7,7),1.5,1.5);
Canny(framegray, canny, p1, p2);
imshow(“canny”, framegray);
imshow(“Preview”,canny);

int num = 0;
for(int y=0;y<canny.size().height;y++)
{
uchar *row = canny.ptr(y);
for(int x=0;x<canny.size().width;x++)
{
if(row[x] <= 128)
{
int area = floodFill(canny, Point(x,y), CV_RGB(0,0,160));
printf(“filling %d, %d gray, area is %d\n”, x, y, area);
if(area>37 && area < 300) num++;
}
}
}
printf(“number is %d\n”, num);
//==============================================
//code dice point recognize end
//==============================================
counter++;
count[num]++;
printf(“=====================================================\n”);
printf(“Total=%4d| One | Two | Three | Four | Five | Six |\n”,counter);
printf(” | %4d|%4d | %4d | %4d | %4d | %4d|\n”,count[1],count[2],count[3],count[4],count[5],count[6]);
printf(“=====================================================\n”);
printf(“Show result delay 3s\n”);
delayshow(3);
int c=waitKey(33);
if(c==27) break;
}

system(“PAUSE”);
CloseHandle(hCom);

return 0;
}

运行结果就是下面这个样子。Console 显示统计结果,旁边一个显示灰度化后的摄像头内容,另外一个显示边缘提取后的结果。

image005

我只做了一个多小时,收集的结果不多,看起来结果并不平均,不知道如果做个一万次之类的会是什么结果。

运行时的视频(刚开始放在Tudou的时候,审核没有通过,估计是因为名称中有“骰子”。后来申诉了一下)

http://www.tudou.com/programs/view/TtqRy-KRr-8/?resourceId=414535982_06_02_99

其实更好的方案是记录下每次的运行结果,因为我发现这个东西每次之间似乎有相关性。比如说这次出现六点,那么下次出现六点的可能性似乎大于 1/6。猜测和骰子机的摇骰子方式有相关性。

最后的最后,吐槽一下电脑的问题:第一个没想到是前面说过的罗技摄像头居然不支持Windows 7,如果你也想做同样的实验需要购买摄像头不妨考虑一下买个二手的微软摄像头,只是外观差一些,效果和支持应该比罗技的好多了;第二个是梅捷 SY-D2700-U3M 的主板,BIOS中居然没有设计风扇温控功能【参考4 提到的Watchdog就是为他设计的】。最近天气热了,硬盘丢失的问题更是频频出现,鲁大师检测CPU温度50左右,主板温度在60左右就会出现这个现象。当我连接一个风扇到上面的时候,5000RPM让人难以忍受。下一个实验就是如何做一个能够调节转速的风扇了。

参考:
参考1:VS2008串口发送参考代码
http://www.lab-z.com/%E4%B8%87%E4%B8%87%E6%B2%A1%E6%83%B3%E5%88%B0%EF%BC%8C%E4%B8%B2%E5%8F%A3%E7%9A%84%E6%95%85%E4%BA%8B/
参考2:超简单的opencv骰子点数识别,效果居然还不错 http://chen-xiao.com/?p=250
参考3:OpenCV的imshow无法正常显示视频http://haibuo1981.iteye.com/blog/1401764
非常感谢作者解决了困惑我一下午的问题,如果你用 cap >> img 这样之后,想再通过显示imShow到屏幕上(特别是在一个循环中),必须使用waitKey(xx)给程序足够的时间来更新画面。
参考4:使用 Arduino 打造一个硬件的Watchdog
http://www.lab-z.com/%E4%BD%BF%E7%94%A8-arduino-%E6%89%93%E9%80%A0%E4%B8%80%E4%B8%AA%E7%A1%AC%E4%BB%B6%E7%9A%84watchdog/

Step to UEFI (11)—- 让程序中断运行的方法

前面介绍了 Pasue 一下的方法,这里再介绍一下让程序停止执行的方法。 和 DOS 不同,Shell中的程序通常都像吃过炫迈口香糖那样—-根本停不下来…..要想能够中止运行,可以通过 Shell Environment 2 特别设置一下。

下面的代码设置了 ESC 为Break 键,运行中可以使用它来终止运行,这里的代码和前面 PauseTest的长得几乎一样:

//
// PauseTest.c
//
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiApplicationEntryPoint.h>
#include <Library/BaseMemoryLib.h>

#define SHELL_INTERFACE_PROTOCOL \
  { \
    0x47c7b223, 0xc42a, 0x11d2, 0x8e, 0x57, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b \
  }
EFI_GUID        ShellInterfaceProtocol  = SHELL_INTERFACE_PROTOCOL;
EFI_GUID		SEGuid = EFI_SE_EXT_SIGNATURE_GUID;
//
// The shell environment is provided by a driver.  The shell links to the
// shell environment for services.  In addition, other drivers may connect
// to the shell environment and add new internal command handlers, or
// internal protocol handlers.
//
#define SHELL_ENVIRONMENT_INTERFACE_PROTOCOL \
  { \
    0x47c7b221, 0xc42a, 0x11d2, 0x8e, 0x57, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b \
  }
EFI_GUID        ShellEnvProtocol = SHELL_ENVIRONMENT_INTERFACE_PROTOCOL;

#define EFI_OUTPUT_PAUSE    0x00000002

typedef struct {
  SHELLENV_EXECUTE          Execute;  // Execute a command line
  SHELLENV_GET_ENV          GetEnv;   // Get an environment variable
  SHELLENV_GET_MAP          GetMap;   // Get mapping tables
  SHELLENV_ADD_CMD          AddCmd;   // Add an internal command handler
  SHELLENV_ADD_PROT         AddProt;  // Add protocol info handler
  SHELLENV_GET_PROT         GetProt;  // Get the protocol ID
  SHELLENV_CUR_DIR          CurDir;
  SHELLENV_FILE_META_ARG    FileMetaArg;
  SHELLENV_FREE_FILE_LIST   FreeFileList;

  //
  // The following services are only used by the shell itself
  //
  SHELLENV_NEW_SHELL        NewShell;
  SHELLENV_BATCH_IS_ACTIVE  BatchIsActive;

  SHELLENV_FREE_RESOURCES   FreeResources;
} EFI_SHELL_ENVIRONMENT;

EFI_SHELL_INTERFACE             *SI;
EFI_SHELL_ENVIRONMENT           *SE;
EFI_SHELL_ENVIRONMENT2          *SE2;

EFI_BOOT_SERVICES     *gBS;
EFI_RUNTIME_SERVICES  *gRT;
EFI_SYSTEM_TABLE      *gST;

//Copy from \Shell\Library\Misc.c
BOOLEAN
GrowBuffer (
  IN OUT EFI_STATUS   *Status,
  IN OUT VOID         **Buffer,
  IN UINTN            BufferSize
  )
/*++

Routine Description:

  Helper function called as part of the code needed
  to allocate the proper sized buffer for various 
  EFI interfaces.

Arguments:

  Status      - Current status

  Buffer      - Current allocated buffer, or NULL

  BufferSize  - Current buffer size needed
    
Returns:
    
  TRUE - if the buffer was reallocated and the caller 
  should try the API again.

--*/
{
  BOOLEAN TryAgain;

  //
  // If this is an initial request, buffer will be null with a new buffer size
  //
  if (NULL == *Buffer && BufferSize) {
    *Status = EFI_BUFFER_TOO_SMALL;
  }
  //
  // If the status code is "buffer too small", resize the buffer
  //
  TryAgain = FALSE;
  if (*Status == EFI_BUFFER_TOO_SMALL) {

    if (*Buffer) {
      FreePool (*Buffer);
    }

    *Buffer = AllocateZeroPool (BufferSize);

    if (*Buffer) {
      TryAgain = TRUE;
    } else {
      *Status = EFI_OUT_OF_RESOURCES;
    }
  }
  //
  // If there's an error, free the buffer
  //
  if (!TryAgain && EFI_ERROR (*Status) && *Buffer) {
    FreePool (*Buffer);
    *Buffer = NULL;
  }

  return TryAgain;
}

//Copy from \Shell\Library\Handle.c
EFI_STATUS
LocateHandle (
  IN EFI_LOCATE_SEARCH_TYPE       SearchType,
  IN EFI_GUID                     * Protocol OPTIONAL,
  IN VOID                         *SearchKey OPTIONAL,
  IN OUT UINTN                    *NoHandles,
  OUT EFI_HANDLE                  **Buffer
  )
/*++

Routine Description:

  Function returns an array of handles that support the requested protocol 
  in a buffer allocated from pool.

Arguments:

  SearchType           - Specifies which handle(s) are to be returned.
  Protocol             - Provides the protocol to search by.   
                         This parameter is only valid for SearchType ByProtocol.
  SearchKey            - Supplies the search key depending on the SearchType.
  NoHandles            - The number of handles returned in Buffer.
  Buffer               - A pointer to the buffer to return the requested array of 
                         handles that support Protocol.

Returns:
  
  EFI_SUCCESS           - The result array of handles was returned.
  EFI_NOT_FOUND         - No handles match the search. 
  EFI_OUT_OF_RESOURCES - There is not enough pool memory to store the matching results.

--*/
{
  EFI_STATUS  Status;
  UINTN       BufferSize;

  //
  // Initialize for GrowBuffer loop
  //
  Status      = EFI_SUCCESS;
  *Buffer     = NULL;
  BufferSize  = 50 * sizeof (EFI_HANDLE);

  //
  // Call the real function
  //
  while (GrowBuffer (&Status, (VOID **) Buffer, BufferSize)) {
    Status = gBS->LocateHandle (
                  SearchType,
                  Protocol,
                  SearchKey,
                  &BufferSize,
                  *Buffer
                  );
  }

  *NoHandles = BufferSize / sizeof (EFI_HANDLE);
  if (EFI_ERROR (Status)) {
    *NoHandles = 0;
  }

  return Status;
}

INTN
CompareGuidx (
  IN EFI_GUID     *Guid1,
  IN EFI_GUID     *Guid2
  )
/*++

Routine Description:

  Compares to GUIDs

Arguments:

  Guid1 - guid to compare
  Guid2 - guid to compare

Returns:
  =  0  if Guid1 == Guid2
  != 0  if Guid1 != Guid2 

--*/
{
  INT32 *g1;
  INT32 *g2;
  INT32 r;

  //
  // Compare 32 bits at a time
  //
  g1  = (INT32 *) Guid1;
  g2  = (INT32 *) Guid2;

  r   = g1[0] - g2[0];
  r |= g1[1] - g2[1];
  r |= g1[2] - g2[2];
  r |= g1[3] - g2[3];

  return r;
}
// Copy from \Shell\Library\Init.c
EFI_STATUS
LibInitializeShellApplication (
  IN EFI_HANDLE                   ImageHandle,
  IN EFI_SYSTEM_TABLE             *SystemTable
  )
{
  EFI_STATUS  Status;
  EFI_HANDLE  *HandleBuffer;
  UINTN       HandleNum;
  UINTN       HandleIndex;
  EFI_GUID         SESGuid         = EFI_SE_EXT_SIGNATURE_GUID;
  
  //
  // Connect to the shell interface
  //
  Status = gBS->HandleProtocol (ImageHandle, &ShellInterfaceProtocol, (VOID *) &SI);
  if (EFI_ERROR (Status)) {
    Print (L"InitShellApp: Application not started from Shell\n");
    gBS->Exit (ImageHandle, Status, 0, NULL);
  }

  //
  // Connect to the shell environment
  //
  Status = gBS->HandleProtocol (
                ImageHandle,
                &ShellEnvProtocol,
                (VOID *) &SE2
                );
  if (EFI_ERROR (Status) || !(CompareGuid (&SE2->SESGuid, &SESGuid) == 0 &&
    (SE2->MajorVersion > EFI_SHELL_MAJOR_VER ||
      (SE2->MajorVersion == EFI_SHELL_MAJOR_VER && SE2->MinorVersion >= 
EFI_SHELL_MINOR_VER))
    )
  ) {
    Status = LocateHandle (
              ByProtocol,
              &ShellEnvProtocol,
              NULL,
              &HandleNum,
              &HandleBuffer
              );
    if (EFI_ERROR (Status)) {
      Print (L"InitShellApp: 1Shell environment interfaces not found\n");
      gBS->Exit (ImageHandle, Status, 0, NULL);
    }

    Status = EFI_NOT_FOUND;
    for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) {
      gBS->HandleProtocol (
           HandleBuffer[HandleIndex],
           &ShellEnvProtocol,
           (VOID *) &SE2
           );
      if (CompareGuidx (&SE2->SESGuid, &SESGuid) == 0)
	  {
        Status = EFI_SUCCESS;
        break;
      }
    }

    FreePool (HandleBuffer);

    if (EFI_ERROR (Status)) {
      Print (L"InitShellApp: 2Shell environment interfaces not found\n");
      gBS->Exit (ImageHandle, Status, Status, NULL);
    }
  }

  SE = (EFI_SHELL_ENVIRONMENT *) SE2;
  
  //
  // Done with init
  //
  return Status;
}

//
// Entry point function 
//
EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
   INTN	i;
   BOOLEAN ExitMark=FALSE;
   
   gST = SystemTable;
   gBS = SystemTable -> BootServices;
   
   LibInitializeShellApplication (ImageHandle,SystemTable);
   
   while (!ExitMark) 
    {
		//Clear Screen
		gST -> ConOut -> ClearScreen(gST->ConOut);
   	    Print(L"You can break by ESC key\n");
		for (i=0;i<80*(25-1);i++)
		{
			if (SE2 -> GetExecutionBreak() ) {ExitMark=TRUE; break;}
			Print(L".");
		} 
	}
	 
  return EFI_SUCCESS;
}

 

运行结果:

BreakTest

代码:

BreakTest

使用Paypal支付外币多付款的问题

如果你使用的是信用卡,那么一定要注意下面的问题:

1.如果你是在国内的 Paypal 注册的,那么无法支付美元。

2.如果你是在国外注册的 Paypal ,那么一定要联系客服(英文服务),否则无法支付美元。

这里解释一下“无法支付美元”是什么意思。比如:你看中了 100美元的货物,然后购买的话,Paypal会先将这100美元转换为 640人民币(比如当天的汇率为6.2,他们会使用比普通中间值要高的汇率!),然后你的信用卡上面会出现你支付了 640人民币的账目,但是月末出账单的时候上面会显示 你有一笔 104.9美元的支付,(银行会使用比如 6.1 来“帮”你折算成美元,因为你的消费并非美元而是“当地货币”),同时银行还会向你收取 1.5% = 1.5美元左右的手续费。这个手续费银行方面的解释是“一般持卡人都是用人民币-美元的双币种卡,在非美元地区使用,就需要先将当地货币转换为美元,而这时候会被国际卡组织收取至少1.5%的货币转换费。”【参考 1】

上面解释了一圈,归结起来就是一句话:你以为自己支付的是美元,实际上却是人民币,因此Paypal和银行都会过来“帮”你转换货币,代价是你要为此多支付4%左右。

下面就是如何解决这个问题:

对于1的情况,Paypal的客服刚开始告诉我说页面可以进行设置,但是我实在无法找到。后来他们改口说请注册国际的 Paypal。之后,我注册了国际的,但是再次支付又出现了同样的问题。他们客服告诉我说这是因为我的信用卡被自动识别为中国区,为我考虑,自动用人民币给我结算。我还和他们确认过在页面上没有相关选项,必须通知他们客服人工进行修改,当然也没有这条必须人工修改的提示. 【参考 2】

所以,新注册并且绑定信用卡之后,请务必联系客服人员,确定币种问题,问题是他们好像只有英文服务哎~ 国内有中文服务,但是很明显他们无法解决问题,并且态度方面要比国际客服差一些。

参考:

1.http://info.cmbchina.com/Stock/Detail.aspx?channel=Mac&topic=GNHG&id=4722460 境外消费用对信用卡可省1.5%货币转换费

2.客服给我的解释。我是想要他们关于这个问题的详细 policy ,但是那个哥们只是给我解释了一下。

Allow me to explain that when you register a PayPal account and add a local credit card to your PayPal account, the primary currency will follow the local currency. For example:

China registered PayPal account, you add a local credit or debit card; the primary currency for the card is in CNY.
Japan registered PayPal account, you add a local credit or debit card; the primary currency for the card is in JPY.
Singapore registered PayPal account, you add a local credit or debit card; the primary currency for the card is in SGD.

However if you have a local credit or debit card that is in USD or another currency, you need to inform PayPal to change the currency for you as this is considered a special case.

I apologize for the inconvenience caused and I appreciate your understanding regarding this matter.

Should you need further assistance at any point of time, please do remember that you have someone right here who is more than happy to assist and resolve your issue for you personally.

Have a wonderful evening ahead!

Thank you for choosing PayPal. Your satisfaction is important to us. We welcome your feedback and hope you recommend us to your friends and family.

Please make sure you have a valid mobile phone number on your PayPal account so that we can contact you if we need to confirm any unusual account activity and protect you from unauthorized account use. To add or update a mobile phone number is easy: Log in to your PayPal account, click ‘Profile’ near the top of the page, and then click ‘Update’ beside ‘Phone.’

Sincerely,
XXXXX
PayPal, an eBay Company

Copyright© 2014 PayPal Inc. All rights reserved.

Consumer advisory: PayPal Pte Ltd, the Holder of the PayPal™ payment service stored value facility, does not require the approval of the Monetary Authority of Singapore. Consumers (users) are advised to read the terms and conditions carefully.

How to use EADK

If you want to use C library in your program such as: printf, scanf……. You should use EADK library in EDK2.

1.Decompress EADK_A2_Release. There are 3 directories. Put them to your EDK2 source directory. In fact you should make sure your EDK2 can build and run NT32 well.

Capture

2.Run edksetup.bat in your EDK directory.

edksetup

3.You can build EADK_A2_Release by using

build -a IA32 -p AppPkg\AppPkg.dsc

3.You well get the first error message.(AppPkg.dsc error 000E)

error1

4.You should modify AppPkg.dsc as below as we just want to test program under NT32:

[LibraryClasses.IA32]
# TimerLib|PerformancePkg/Library/DxeTscTimerLib/DxeTscTimerLib.inf
## Comment out the above line and un-comment the line below for running under Nt32 emulation.
TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf

5.Build again and your will get the second error message (time.h Error C2220)

error2

6.The solution is simple. Use the Notepad to open the time.h and save again.

7.At last all the demos can be build. You can get main.efi hello.efi and Enquire.efi. They can be run in NT32 emulation environment.

They will be placed at “\Build\AppPkg\DEBUG_VS2008\IA32” after compiling. And you can copy them to “\Build\NT32\DEBUG_VS2008\IA32”. After that they can be seen under fsnt0:

result

8.You can use printf in your program now. Ex.

int
EFIAPI
main (
IN int Argc,
IN char **Argv
)
{

puts(“Hello there fellow Programmer.”);
puts(“Welcome to the world of EDK II.”);

printf(“lab-z.com %x\n”,8212);

return 0;
}

result2

<2016> I find it seems to be hard to download an EADK package from internet, and I put one here EadkPkg_A2
reference:
1.http://www.lab-z.com/step-to-uefi-shell-6-shell-%E4%B8%AD%E4%BD%BF%E7%94%A8-float/

2.http://biosren.com/viewthread.php?tid=5651&fromuid=6339]http://biosren.com/viewthread.php?tid=5651&fromuid=6339 .UEFI 实战(1) 配置开发环境

D12 芯片的 0xFD Command在哪?

有人提了这么一个问题:

USB芯片PDIUSBD12读CHIP ID命令在手册中怎么找不到?

刚开始我以为只是没有拿到完整版的手册,后来找了一份比较新的结果里面也没有

PDIUSBD12D-0.9

遇到这样的情况,通常是要去找找 AP Note,找了一下还真找到了

What is the command to read the chip ID of the PDIUSBD12 and what is the chip ID?
The command to read the chip ID of the PDIUSBD12 is FDh and the expected value is 1012h.

PDIUSBD12_FAQ

最后一个没想明白的是,为毛我打开PDF中的网站 http://www.stnwireless.com/ 是下面的内容?莫非这个公司倒闭了,域名也卖掉了?

nxp