opencv - 在 OpenCV 中使用 Windows 剪贴板图像
问题描述
我正在尝试使用 win32api 将剪贴板位图数据转换为 opencv Mat 对象。
我尝试了以下方法:
#include <iostream>
#include <windows.h>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;
int main(int argc, char *argv[]) {
OpenClipboard(NULL);
HGLOBAL ClipboardDataHandle = (HGLOBAL)GetClipboardData(CF_DIBV5);
if(ClipboardDataHandle){
BITMAPINFOHEADER *BitmapInfoHeader = (BITMAPINFOHEADER *)GlobalLock(ClipboardDataHandle);
if(BitmapInfoHeader){
Mat mat(BitmapInfoHeader->biHeight, BitmapInfoHeader->biWidth, CV_8UC4);
memcpy(mat.data, BitmapInfoHeader, GlobalSize(ClipboardDataHandle));
cvtColor(mat, mat, COLOR_BGR2GRAY);
threshold(mat, mat, 120, 255, THRESH_BINARY);
imwrite("res.bmp", mat);
GlobalUnlock(BitmapInfoHeader);
}
}
CloseClipboard();
}
这解决了很多问题。
这在大多数情况下都适用于垂直翻转问题。
并且在复制包含透明像素信息的图像时,它以退出代码 0xc0000374(A 堆已损坏)中止。
我认为问题在于Mat的第三个参数固定为CV_8UC4。
如果将其保存到文件并再次读取,则没有问题:
#include <iostream>
#include <windows.h>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;
int main(int argc, char *argv[]) {
OpenClipboard(NULL);
HGLOBAL ClipboardDataHandle = (HGLOBAL)GetClipboardData(CF_DIBV5);
if(ClipboardDataHandle){
BITMAPINFOHEADER *BitmapInfoHeader = (BITMAPINFOHEADER *)GlobalLock(ClipboardDataHandle);
if(BitmapInfoHeader){
SIZE_T ClipboardDataSize = GlobalSize(ClipboardDataHandle);
INT PixelDataOffset = BitmapInfoHeader->biSize;
if (BitmapInfoHeader->biSize == sizeof(BITMAPINFOHEADER))
{
if (BitmapInfoHeader->biBitCount > 8)
{
if (BitmapInfoHeader->biCompression == BI_BITFIELDS)
{
PixelDataOffset += 3 * sizeof(RGBQUAD);
}
else if (BitmapInfoHeader->biCompression == 6)
{
PixelDataOffset += 4 * sizeof(RGBQUAD);
}
}
}
if (BitmapInfoHeader->biClrUsed > 0)
{
PixelDataOffset += BitmapInfoHeader->biClrUsed * sizeof(RGBQUAD);
}
else
{
if (BitmapInfoHeader->biBitCount <= 8)
{
PixelDataOffset += sizeof(RGBQUAD) << BitmapInfoHeader->biBitCount;
}
}
BITMAPFILEHEADER BitmapFileHeader = {};
BitmapFileHeader.bfType = 0x4D42;
BitmapFileHeader.bfSize = (DWORD)(sizeof(BITMAPFILEHEADER) + ClipboardDataSize);
BitmapFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + PixelDataOffset;
HANDLE FileHandle = CreateFileA("temp.bmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (FileHandle != INVALID_HANDLE_VALUE)
{
DWORD dummy = 0;
WriteFile(FileHandle, &BitmapFileHeader, sizeof(BITMAPFILEHEADER), &dummy, NULL);
WriteFile(FileHandle, BitmapInfoHeader, (DWORD)ClipboardDataSize, &dummy, NULL);
CloseHandle(FileHandle);
}
GlobalUnlock(BitmapInfoHeader);
}
}
CloseClipboard();
Mat mat = imread("temp.bmp");
cvtColor(mat, mat, COLOR_BGR2GRAY);
threshold(mat, mat, 120, 255, THRESH_BINARY);
imwrite("res.bmp", mat);
}
这很好用。没有翻转问题,也没有错误。但我不想使用临时文件。请帮忙。
解决方案
我还找不到解决方案。
只是我回答自己,因为经过大量的努力,我找到了一个临时的方法。
我需要很多反馈,因为对这段代码没有信心。
#include <iostream>
#include <windows.h>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;
int main(int argc, char *argv[]) {
if(IsClipboardFormatAvailable(CF_DIBV5)){
OpenClipboard(NULL);
HGLOBAL clipboard = GetClipboardData(CF_DIBV5);
if(clipboard){
BITMAPV5HEADER* bitmapV5Header = (BITMAPV5HEADER*)GlobalLock(clipboard);
if(bitmapV5Header){
int type;
switch(bitmapV5Header->bV5BitCount){
case 32:
{
type = CV_8UC4;
break;
}
case 24:
{
type = CV_8UC3;
break;
}
default:
{
type = -1;
std::cout << "no support" << std::endl;
break;
}
}
if(type != -1){
Mat tmp(bitmapV5Header->bV5Height, bitmapV5Header->bV5Width, type, (BYTE*)bitmapV5Header + (GlobalSize(clipboard) - bitmapV5Header->bV5SizeImage), bitmapV5Header->bV5SizeImage / bitmapV5Header->bV5Height); // data not copy
Mat mat;
flip(tmp, mat, 0); // flip with data copy
cvtColor(mat, mat, COLOR_BGR2GRAY); // just for test.
threshold(mat, mat, 80, 255, THRESH_BINARY); // just for test.
imwrite("result.png", mat);
}
GlobalUnlock(clipboard);
}
}
CloseClipboard();
}
}
我认为“bV5BitCount”值不是 24 和 32 的情况会更多。
而且我仍然不知道垂直翻转问题的原因。但是由于我在使用 step 或 stride 时找不到复制数据的方法,因此使用 openCV,同时翻转和复制。
推荐阅读
- python - 使用日期的动态 df len
- ruby-on-rails - 如何使用 Ruby 动态创建 HTML 文件?
- vue.js - Vue.js 选择的选项不是基于值
- python - PYTHON - 查找子字符串“(DefinedBeginOfTheString)(anySubstring,没关系)(DefinedEndOfTheString)”
- c++ - 在 C++ Primer 第 5 版 shared_ptr 中发现错误
- c++ - 在Linux上的单线程c ++ tcp客户端中阻止读取与选择
- r - 模拟广义极值分布
- r - 在会话期间以闪亮的方式更新输入和输出的选择(值)
- python - 在创建新的组合列名 Pandas 时将多个 datetimeIndex 组合成一行
- ios - Xcode Admob 找不到或使用自动链接框架“UniformTypeIdentifiers”