在OpenCV中保存图像

35

我是OpenCV的新手,正在尝试捕获一张图片并将其保存到文件中。下面是我发布的参考代码。

jpg文件已经被保存了,但是它是黑色的。

// Capture the Image from the webcam
CvCapture *pCapturedImage = cvCreateCameraCapture(0);

// Get the frame
IplImage *pSaveImg = cvQueryFrame(pCapturedImage);

// Save the frame into a file
cvSaveImage("test.jpg". ,pSaveImg); // A JPG FILE IS BEING SAVED
                                    // OF 6KB , BUT IT IS BLACK

所有功能都是成功的。我已经在XP和Vista上尝试了上述代码 - 结果在两者上都是黑色图像。请告诉我我错过了什么。

15个回答

31
如果您使用C++,最好使用C++接口:
using namespace cv;
// Capture the Image from the webcam
VideoCapture cap(0);

// Get the frame
Mat save_img; cap >> save_img;

if(save_img.empty())
{
  std::cerr << "Something is wrong with the webcam, could not get frame." << std::endl;
}
// Save the frame into a file
imwrite("test.jpg", save_img); // A JPG FILE IS BEING SAVED

我一直在跟随OpenCV教程,这是不同的东西吗? - Sujay Ghosh

5
根据我的经验,当使用不同于8位的比特深度矩阵调用SaveImage时,OpenCV会输出一张黑色图像。实际上,这在某种程度上已经有所记录:
只有单通道或三通道(按'BGR'通道顺序)的8位图像可以使用此函数保存。如果格式、深度或通道顺序不同,请在保存之前使用cvCvtScalecvCvtColor进行转换,或使用通用的cvSave将图像保存为XML或YAML格式。
在您的情况下,您可以首先调查捕获的图像类型,更改捕获属性(我认为CV_CAP_PROP_CONVERT_RGB可能很重要),或在之后手动进行转换。
以下是使用OpenCV将图像转换为8位表示的示例。这里的cc是一个原始类型为CV_32FC1的矩阵,cc8u是它的缩放版本,实际上是由SaveImage写入的:
# I want to save cc here
cc8u = CreateMat(cc.rows, cc.cols, CV_8U)
ccmin,ccmax,minij,maxij = MinMaxLoc(cc)
ccscale, ccshift = 255.0/(ccmax-ccmin), -ccmin
CvtScale(cc, cc8u, ccscale, ccshift)
SaveImage("cc.png", cc8u)

抱歉,以下是Python代码,但是将其翻译成C/C++应该很容易。


5
有时候第一次调用cvQueryFrame()返回的是空图像。可以尝试以下方法:
IplImage *pSaveImg = cvQueryFrame(pCapturedImage);
pSaveImg = cvQueryFrame(pCapturedImage);

如果这样做没有起作用,尝试自动选择采集设备:
CvCapture *pCapturedImage = cvCreateCameraCapture(-1);

或者您可以尝试选择其他捕获设备,其中n=1,2,3 ...

CvCapture *pCapturedImage = cvCreateCameraCapture(n);

PS:我认为您对于变量名称所表示的捕获图像存在误解。pCapturedImage变量不是一个图像,而是一个捕获。您可以从捕获中“读取”图像。


我仍然得到一张黑色的图像。我甚至在一个while循环中尝试了这个方法,当按下“q”键时会停止。我还使用cvVideoWriter,以便将捕获的帧保存到视频文件(avi)中,但我仍然得到一个内容为黑色的文件。我需要安装任何编解码器才能使OpenCV正常运行吗?谢谢, Sujay - Sujay Ghosh
我不确定我能否进一步帮助你。 - nimcap

3

抱歉如果这显得太明显了。你确定摄像头被OpenCV正确地识别和检测到了吗?换句话说,当你将捕获的帧重定向到“highGui”窗口时,你是否能够得到图像?例如:

 frame = cvQueryFrame( capture );
 cvNamedWindow( "myWindow", CV_WINDOW_AUTOSIZE );
 cvShowImage( "myWindow", frame );

这段代码也给我一个黑色图像。我需要安装编解码器,还是有任何依赖关系?我的网络摄像头正在启动,但是出现了黑色图像。 - Sujay Ghosh

3
我知道问题出在哪里了! 你在"test.jpg"后面加了一个句点! cvSaveImage("test.jpg"., pSaveImg); 我可能说得不对,但我认为这样不好!

2

我曾经遇到过与我的微软网络摄像头类似的问题。我在Matlab的图像获取工具箱中查看,发现最大支持分辨率为640*480。

我只需更改openCV中的代码并添加:

cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 352); 
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 288);

在使用cvQueryFrame函数之前,要确定下一个支持的分辨率并跳过一些初始帧,然后保存图像,最终使其工作。

我分享我的可用代码

#include "cv.h" 
#include "highgui.h" 
#include <stdio.h> 



using namespace cv;
using namespace std;

int main() 
{
CvCapture* capture = cvCaptureFromCAM( CV_CAP_ANY );
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 352); 
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 288)


 // Get one frame
IplImage* frame;

for (int i = 0; i < 25; i++) 
{
frame = cvQueryFrame( capture );
}


printf( "Image captured \n" );  
//IplImage* RGB_frame = frame;
//cvCvtColor(frame,RGB_frame,CV_YCrCb2BGR);
//cvWaitKey(1000);
cvSaveImage("test.jpg" ,frame);
//cvSaveImage("cam.jpg" ,RGB_frame);

printf( "Image Saved \n" );

//cvWaitKey(10);

// Release the capture device housekeeping
cvReleaseCapture( &capture );
//cvDestroyWindow( "mywindow" );
return 0;
}

我的建议:

  1. 不要使用最大分辨率抓取帧
  2. 跳过一些帧以进行正确的相机初始化

1

我在Windows Vista上遇到了同样的问题,我只是在cvQueryFrame之前添加了这段代码:

cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 720);
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 480);

1
我使用以下代码来捕获图像:
CvCapture* capture = cvCaptureFromCAM( CV_CAP_ANY );
if(!capture) error((char*)"No Capture");
IplImage *img=cvQueryFrame(capture);

我确定这个是有效的


1
SayntLewis是正确的。当您使用cvCaptureFromCAM激活相机时,自动白平衡尚未调整(这是一个缓慢的过程),因此您可能会在第一帧上获得大部分白色或大部分黑色(取决于相机和照明条件)。 当场景的照明突然改变时也会发生同样的情况。 打开相机后等待一段时间,刷新缓冲区,然后您就可以开始了。

1

很抱歉翻出了一篇旧帖,但我想为那些遇到这个问题的人提供另一个答案。

我也遇到了同样的问题。无论我做什么,图像看起来都是完全黑色的。我尝试连续调用cvQueryFrame多次,并注意到当我调用5次或更多次时,我可以看到图像。所以我开始逐个删除调用,看看“断点”在哪里。最终我发现,随着每个调用的删除,图像变得越来越暗。只进行一次调用提供了一个几乎完全黑色的图像,但如果我非常仔细地观察,我可以看到我的图像。

我尝试了10次连续调用来测试我的理论,果然,我得到了一个非常明亮的图像,考虑到我在一个昏暗的房间里。希望这就是你遇到的同样的问题。

我对成像不太了解,但似乎连续调用cvQueryFrame会增加相机的曝光时间。这确实解决了问题,尽管它似乎不是最优雅的解决方案。我将尝试找到一个参数,以增加曝光,或者可能是其他一些参数,以使我的图像变亮。

祝你好运!


谢谢Sayn,我会尝试一下。 - Sujay Ghosh
这与曝光无关,而是你的相机自动调节到当前房间的光线条件。由于光线不足,相机软件会进行补偿,但这并非瞬间完成。 - Clément

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接