如何在Windows终端使用网络摄像头拍照

huangapple go评论92阅读模式
英文:

How Take A Picture Using Webcam Windows Terminal

问题

下面的代码旨在使用Windows API通过网络摄像头拍照。当我运行代码时,网络摄像头的LED灯会亮起(表示已调用),持续几秒钟,然后保存PNG图像。然而,保存的图像完全由黑色像素填充(3 KB)。我对Windows API不熟悉,所以解决这个问题可能很简单。有人能猜到出了什么问题吗?

package main

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"syscall"
	"unsafe"
)

var (
	avicap32                    = syscall.NewLazyDLL("avicap32.dll")
	proccapCreateCaptureWindowA = avicap32.NewProc("capCreateCaptureWindowA")

	user32           = syscall.NewLazyDLL("user32.dll")
	procSendMessageA = user32.NewProc("SendMessageA")
)

func CaptureWebcam() {
	var name = "WebcamCapture"
	handle, _, _ := proccapCreateCaptureWindowA.Call(uintptr(unsafe.Pointer(&name)), 0, 0, 0, 320, 240, 0, 0)
	procSendMessageA.Call(handle, 0x40A, 0, 0)  //WM_CAP_DRIVER_CONNECT
	procSendMessageA.Call(handle, 0x432, 30, 0) //WM_CAP_SET_PREVIEW
	procSendMessageA.Call(handle, 0x43C, 0, 0)  //WM_CAP_GRAB_FRAME
	procSendMessageA.Call(handle, 0x41E, 0, 0)  //WM_CAP_EDIT_COPY
	procSendMessageA.Call(handle, 0x40B, 0, 0)  //WM_CAP_DRIVER_DISCONNECT
	camera, err := os.Create("Image.png")
	if err != nil {
		fmt.Println(err)
		return
	}
	clip, err := readClipboard()
	if err != nil {
		fmt.Println(err)
		return
	}
	_, err = io.Copy(camera, clip)
	if err != nil {
		fmt.Println(err)
		return
	}
	camera.Close()
}

func readClipboard() (io.Reader, error) {
	f, err := ioutil.TempFile("", "")
	if err != nil {
		fmt.Println(err)
		return nil, err
	}
	f.Close()
	_, err = exec.Command("PowerShell", "-Command", "Add-Type", "-AssemblyName", fmt.Sprintf("System.Windows.Forms;$clip=[Windows.Forms.Clipboard]::GetImage();if ($clip -ne $null) { $clip.Save('%s') };", f.Name())).CombinedOutput()
	if err != nil {
		fmt.Println(err)
		return nil, err
	}
	r := new(bytes.Buffer)
	file, err := os.Open(f.Name())
	if err != nil {
		fmt.Println(err)
		return nil, err
	}
	if _, err := io.Copy(r, file); err != nil {
		fmt.Println(err)
		return nil, err
	}
	file.Close()
	os.Remove(f.Name())
	return r, nil
}

func main() {
	CaptureWebcam()
}
英文:

The code below aims to take a picture using the webcam via windows API. When I run the code the led of the webcam turns on (what indicates that it was called) for few seconds and then saves the PNG image, nevertheless it is complete filled of back pixels (3 kb). I am not familiar with windows API, so maybe solve this issue could be very simple. Anyone can guess what is going on?

package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"syscall"
"unsafe"
)
var (
avicap32                    = syscall.NewLazyDLL("avicap32.dll")
proccapCreateCaptureWindowA = avicap32.NewProc("capCreateCaptureWindowA")
user32           = syscall.NewLazyDLL("user32.dll")
procSendMessageA = user32.NewProc("SendMessageA")
)
func CaptureWebcam() {
var name = "WebcamCapture"
handle, _, _ := proccapCreateCaptureWindowA.Call(uintptr(unsafe.Pointer(&name)), 0, 0, 0, 320, 240, 0, 0)
procSendMessageA.Call(handle, 0x40A, 0, 0)  //WM_CAP_DRIVER_CONNECT
procSendMessageA.Call(handle, 0x432, 30, 0) //WM_CAP_SET_PREVIEW
procSendMessageA.Call(handle, 0x43C, 0, 0)  //WM_CAP_GRAB_FRAME
procSendMessageA.Call(handle, 0x41E, 0, 0)  //WM_CAP_EDIT_COPY
procSendMessageA.Call(handle, 0x40B, 0, 0)  //WM_CAP_DRIVER_DISCONNECT
camera, err := os.Create("Image.png")
if err != nil {
fmt.Println(err)
return
}
clip, err := readClipboard()
if err != nil {
fmt.Println(err)
return
}
_, err = io.Copy(camera, clip)
if err != nil {
fmt.Println(err)
return
}
camera.Close()
}
func readClipboard() (io.Reader, error) {
f, err := ioutil.TempFile("", "")
if err != nil {
fmt.Println(err)
return nil, err
}
f.Close()
_, err = exec.Command("PowerShell", "-Command", "Add-Type", "-AssemblyName", fmt.Sprintf("System.Windows.Forms;$clip=[Windows.Forms.Clipboard]::GetImage();if ($clip -ne $null) { $clip.Save('%s') };", f.Name())).CombinedOutput()
if err != nil {
fmt.Println(err)
return nil, err
}
r := new(bytes.Buffer)
file, err := os.Open(f.Name())
if err != nil {
fmt.Println(err)
return nil, err
}
if _, err := io.Copy(r, file); err != nil {
fmt.Println(err)
return nil, err
}
file.Close()
os.Remove(f.Name())
return r, nil
}
func main() {
CaptureWebcam()
}

答案1

得分: 1

似乎数据是CF_BITMAP剪贴板格式。您还可以直接使用Clipboard API

以下是来自文档示例的代码片段:

case CF_BITMAP: 
    hdcMem = CreateCompatibleDC(hdc); 
    if (hdcMem != NULL) 
    { 
        if (OpenClipboard(hwnd)) 
        { 
            hbm = (HBITMAP) GetClipboardData(uFormat); 
            SelectObject(hdcMem, hbm); 
            GetClientRect(hwnd, &rc); 

            BitBlt(hdc, 0, 0, rc.right, rc.bottom, 
                hdcMem, 0, 0, SRCCOPY); 
            CloseClipboard(); 
        } 
        DeleteDC(hdcMem); 
    } 
    break;

另附来自Easy Digital Camera Connection的代码:

void CYourProject::OnTimer(UINT nIDEvent) 
{
 if(nIDEvent==1)// First Timer
 {
   capGrabFrame(hWndC); // 从相机中获取一帧图像的简单宏。
   capEditCopy(hWndC);  // 编辑图像的副本的简单宏。
   OpenClipboard();     // 类似虚拟内存。
 
   // m_hBmp 是位图的句柄。
   m_hBmp = (HBITMAP)::GetClipboardData(CF_BITMAP); 
   CloseClipboard();
 
   //...
 }
 CDialog::OnTimer(nIDEvent);
}
英文:

It seems the data is CF_BITMAP Clipboard Format. Also you can use Clipboard API directly.

The code snippet from document sample.

                case CF_BITMAP: 
hdcMem = CreateCompatibleDC(hdc); 
if (hdcMem != NULL) 
{ 
if (OpenClipboard(hwnd)) 
{ 
hbm = (HBITMAP) 
GetClipboardData(uFormat); 
SelectObject(hdcMem, hbm); 
GetClientRect(hwnd, &rc); 
BitBlt(hdc, 0, 0, rc.right, rc.bottom, 
hdcMem, 0, 0, SRCCOPY); 
CloseClipboard(); 
} 
DeleteDC(hdcMem); 
} 
break;

Attached another Code from Easy Digital Camera Connection.

void CYourProject::OnTimer(UINT nIDEvent) 
{
if(nIDEvent==1)// First Timer
{
capGrabFrame(hWndC); // simple macro that sample a single frame from the 
// camera.
capEditCopy(hWndC);  // simple macro that edit a copy of the frame.
OpenClipboard();     //like virtual memory.
//m_hBmp is a Handle to Bitmap.
m_hBmp = (HBITMAP)::GetClipboardData(CF_BITMAP); 
CloseClipboard();
//...
}
CDialog::OnTimer(nIDEvent);
}

huangapple
  • 本文由 发表于 2022年6月16日 12:10:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/72640357.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定