我制作了一个程序,可以将视频转换为调整大小的 ASCII 动画,但是
Mat frame
只捕获整个视频左上角的一部分。相应地,Mat
的深度和通道为0和1。即使 at<uchar>
返回为空,如果没有 Mat
,该程序也无法运行?
#include <iostream>
#include <vector>
#include <chrono>
#include <thread>
#include <Windows.h>
#include <mmsystem.h>
#include <opencv2/opencv.hpp>
#pragma comment(lib, "winmm.lib")
void checkForOpenCV()
{
if(cv::getCPUTickCount == 0)
{
std::cout << "OpenCV is not detected." << '\n';
}
else
{
std::cout << "OpenCV is detected." << '\n';
}
}
cv::VideoCapture openVid(std::string &filePath)
{
cv::VideoCapture cap{filePath};
if(!cap.isOpened())
{
std::cout << "The file cannot be accessed." << '\n';
exit(-1);
}
else
{
std::cout << "File is accessed." << '\n';
}
return cap;
}
char brightness2Ascii(int brightness, std::string asciiCharset)
{
int index(brightness * asciiCharset.size() / 256);
return asciiCharset[index];
}
int main()
{
checkForOpenCV();
std::string filePath{R"(C:\Users\Harold.DESKTOP-UJ6F4M4\Videos\video.mp4)"};
cv::VideoCapture cap{openVid(filePath)};
double fps{cap.get(cv::CAP_PROP_FPS)};
std::cout << fps << '\n';
int width(cap.get(cv::CAP_PROP_FRAME_WIDTH));
int height(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
int aspectRatio{12};
std::cout << width << " x " << height << '\n';
std::vector<cv::Mat> totalFrames{};
cv::Mat frame{};
int depth{frame.depth()};
int channels{frame.channels()};
while(cap.read(frame))
{
cv::resize(frame, frame, cv::Size(width / aspectRatio, height / aspectRatio), 0, 0, cv::INTER_LINEAR);
totalFrames.push_back(frame.clone());
}
cap.release();
for(const auto &frame:totalFrames)
{
std::string asciiArt{};
for(int i{0}; i < frame.rows; i++)
{
for(int j{0}; j < frame.cols; j++)
{
const std::string asciiCharset{" .'-=*%#@"}; // {" .'-=*%#@"} {"@ "}
int brightness{frame.at<uchar>(i, j)};
char pixelChar{brightness2Ascii(brightness, asciiCharset)};
asciiArt += pixelChar;
}
asciiArt += '\n';
}
std::cout << depth << '\n' << channels << '\n';
std::cout << asciiArt;
cv::waitKey(fps / 2);
}
return 0;
}
我尝试创建一个单独的
Mat resizedFrame
,以及为asciiChar
声明单独的宽度和高度,但无济于事。最初,我认为问题是由于在预加载所有框架后调整框架大小而出现的,但是在预加载循环中重新定位 resize()
后,我不再那么确定了。
事实证明,如果我将
frame
与它一起使用,我需要将 GRAY Mat
转换为 at<uchar>
。我没有这样做,因为视频已经是黑白的,但 OpenCV 无论如何都将其转换为 BGR。对于非灰色垫子,请使用 at<Vec3b>()
代替。
for(const auto &frame : totalFrames)
{
cv::cvtColor(frame, grayFrame, cv::COLOR_BGR2GRAY);
cv::resize(grayFrame, grayFrame, cv::Size(2 * width / aspectRatio, height / aspectRatio), 0, 0, cv::INTER_LINEAR);
std::string asciiArt{};
for(int i{0}; i < grayFrame.rows; i++)
{
for(int j{0}; j < grayFrame.cols; j++)
{
const std::string asciiCharset{".'-=*%#@"}; // {" .'-=*%#@"} {"@ "}
int brightness{grayFrame.at<uchar>(i, j)};
char pixelChar{brightness2Ascii(brightness, asciiCharset)};
asciiArt += pixelChar;
}
asciiArt += '\n';
}
std::cout << asciiArt;
Sleep(1000 / fps);
}