使用OpenCV的C语言代码无法将帧写入视频,输出视频为空
Got it, let's tackle this blank video issue—this is a super common pitfall when using OpenCV's old C API for video writing. Let's go through the most likely culprits one by one, and fix your code step by step.
1. First, Check if the Video Writer Actually Created Successfully
The cvCreateVideoWriter function returns NULL silently if it fails (bad path, unsupported codec, wrong dimensions, etc.), and writing frames to a NULL writer does nothing—resulting in that empty 0-length video. Always add a check:
CvVideoWriter* vWriter = cvCreateVideoWriter(path, CV_FOURCC('N', 'A', 'V', 'I'), 50, cvSize(maxWidth, maxHeight), 1); if (!vWriter) { fprintf(stderr, "Error: Failed to create video writer! Check path, codec, or dimensions.\n"); free(images); return -1; // or handle error appropriately }
2. Ensure Frame Dimensions Match the Video's Resolution
If your frames have a different width/height than what you passed to cvCreateVideoWriter, cvWriteFrame will silently skip writing them. You need to either:
- Resize frames to match
maxWidth/maxHeight, or - Double-check that
maxWidth/maxHeightare correctly set to match your frames.
Here's how to add resizing (and frame validity checks) to your loop:
int i; for (i = 0; i < size; i++) { IplImage* frame = images[i]; // Skip if frame is NULL (invalid) if (!frame) { fprintf(stderr, "Warning: Frame %d is NULL, skipping.\n", i); continue; } // Resize frame if dimensions don't match if (frame->width != maxWidth || frame->height != maxHeight) { fprintf(stderr, "Resizing frame %d from %dx%d to %dx%d\n", i, frame->width, frame->height, maxWidth, maxHeight); IplImage* resized_frame = cvCreateImage(cvSize(maxWidth, maxHeight), frame->depth, frame->nChannels); cvResize(frame, resized_frame); cvWriteFrame(vWriter, resized_frame); cvReleaseImage(&resized_frame); } else { cvWriteFrame(vWriter, frame); } }
3. Match Frame Channel Count to the isColor Parameter
The last argument to cvCreateVideoWriter (the 1 in your code) tells OpenCV you're writing color frames (3 channels, BGR format). If your frames are grayscale (1 channel), this will cause silent failures. Fix this by setting isColor based on your frames' channel count:
// Check the first valid frame's channel count (adjust if first frame might be NULL) int is_color = (images[0] && images[0]->nChannels == 3) ? 1 : 0; CvVideoWriter* vWriter = cvCreateVideoWriter(path, CV_FOURCC('M', 'P', '4', 'V'), 50, cvSize(maxWidth, maxHeight), is_color);
4. Try a Different Codec
The NAVI codec (CV_FOURCC('N','A','V','I')) is an older FFmpeg codec that might not be supported in your environment. Swap it for a more widely supported option:
- MP4:
CV_FOURCC('M','P','4','V') - DIVX (good for Windows):
CV_FOURCC('D','I','V','X') - H.264 (if your OpenCV is built with FFmpeg support):
CV_FOURCC('H','2','6','4')
If you're on a system with a GUI, you can even pass -1 instead of the fourcc code—this will pop up a dialog to select a supported codec (handy for debugging).
5. Flush Before Releasing the Writer
While cvReleaseVideoWriter should flush pending frames to disk, sometimes explicitly calling cvFlushVideoWriter ensures all data is written, especially if you're dealing with large frame sets:
// After writing all frames cvFlushVideoWriter(vWriter); cvReleaseVideoWriter(&vWriter); free(images);
6. Verify Path Permissions and Validity
Make sure the target path exists (if you're writing to a subdirectory, create it first) and your program has write permissions. You can use the access function to check this before creating the writer:
#include <unistd.h> // For access() #include <string.h> // For strrchr() // Check if the directory is writable char dir_buf[256]; strncpy(dir_buf, path, sizeof(dir_buf)-1); char* last_slash = strrchr(dir_buf, '/'); if (last_slash) { *last_slash = '\0'; // Isolate the directory path if (access(dir_buf, W_OK) != 0) { fprintf(stderr, "Error: Directory %s is not writable!\n", dir_buf); free(images); return -1; } }
Final Modified Code Snippet
Putting all these fixes together, your code would look something like this:
#include <stdio.h> #include <unistd.h> #include <string.h> #include <opencv/cv.h> #include <opencv/highgui.h> // ... your other code ... // Check directory writability first char dir_buf[256]; strncpy(dir_buf, path, sizeof(dir_buf)-1); char* last_slash = strrchr(dir_buf, '/'); if (last_slash) { *last_slash = '\0'; if (access(dir_buf, W_OK) != 0) { fprintf(stderr, "Error: Directory %s is not writable!\n", dir_buf); free(images); return -1; } } // Validate first frame and set is_color int is_color = 0; if (size > 0 && images[0]) { is_color = (images[0]->nChannels == 3) ? 1 : 0; } // Create video writer with error check CvVideoWriter* vWriter = cvCreateVideoWriter(path, CV_FOURCC('M', 'P', '4', 'V'), 50, cvSize(maxWidth, maxHeight), is_color); if (!vWriter) { fprintf(stderr, "Error: Failed to create video writer! Check codec, path, or dimensions.\n"); free(images); return -1; } // Write frames with resizing and validity checks int i; for (i = 0; i < size; i++) { IplImage* frame = images[i]; if (!frame) { fprintf(stderr, "Warning: Frame %d is NULL, skipping.\n", i); continue; } if (frame->width != maxWidth || frame->height != maxHeight) { IplImage* resized = cvCreateImage(cvSize(maxWidth, maxHeight), frame->depth, frame->nChannels); cvResize(frame, resized); cvWriteFrame(vWriter, resized); cvReleaseImage(&resized); } else { cvWriteFrame(vWriter, frame); } } // Flush and clean up cvFlushVideoWriter(vWriter); cvReleaseVideoWriter(&vWriter); free(images);
Start with checking the writer's return value first—that's the most likely fix. If that's okay, move on to verifying frame dimensions and codec support.
内容的提问来源于stack exchange,提问作者aviad1

