파티클 효과는 직접 구현해도 되지만, 보통 직접 구현보다는 이미 있는 gif나 mov, mp4로 많이 구현한다.
그냥 합치면 되는 거 아니냐 라고 할 수 있겠지만, 고려할 게 세 가지가 있다.
1. 두 개의 동영상이 시간적으로 다르니 (보통 파티클은 짧으니) 파티클을 무한 반복 해줘야한다.
2. 파티클의 속도를 조절하고 싶은데, 시간적으로 다르니 waitKey를 쓸 수 없다
3. 부드럽게 합치기
라는 점이다.
일반적으로 동영상 속도 조절이라고 치면 waitKey를 쓰거나 set prop fps를 사용해서 조절하는 데, 웹캠은 몰라도 동영상 같은 경우에는 ( 내 경우엔 ) 이걸로 파티클 속도가 조절이 안되었다.
뭐 알려주는 블로그 글도 없어서 누군가에게 도움이 될까봐 그냥 올려본다.
알고리즘적으로 해결방법을 먼저 말해주자면,
1. 파티클 무한 반복 : empty()를 활용해서 끝나면 다시 open 시켜준다.
2. 속도 조절 : 조절하고 싶은 속도만큼 해당 프레임을 건너뛰면 된다.
3. 합치기 : addweighted를 활용한다.
보통 속도 조절하는 용도로 WaitKey를 쓰게되는 데, 동영상 하나면 몰라도 두개면 같이 느려지기 때문에 안된다. 그래서 나 같은 경우에는 frame을 건너뛰는 형식으로 만들었는데 더 좋은 아이디어 있으면 댓글 부탁한다.
#include <stdio.h>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(int argc, char *argv[])
{
// particle variables
string particleEffectPath = "particle.mp4";
VideoCapture particleEffect;
bool particleEffectOn = true; // you can turn on/off particle effects
Mat particleEffectFrame;
// camera variables
string camPath = "otherVideo.mp4";
int camFPS;
VideoCapture cam;
Mat frame;
// speed related variables (between camera and particle)
int speed = 2; // speed going slower when "speed" Integer increases
int particleEffectFrameNumber = 0; // dont touch this
// initialize particle and video
cam.open(camPath); // you can set number when you want to open webcamera
particleEffect.open(particleEffectPath);
// check whether videos opened or not
if (!particleEffect.isOpened()){
cout << "Cannot open particles, path : " << particleEffectPath << endl;
return 0;
}
else
cout << "Particle is open, path : " << particleEffectPath << endl;
if (!cam.isOpend()){
cout << "Cannot open video or camera, path : " << camPath << endl;
return 0;
}
else
cout << "Camera/Video is open, path : " << camPath << endl;
while (true) {
cam.read(frame);
if (particleEffectOn) {
if (particleEffectFrameNumber == dist) {
particleEffectFrameNumber = 0;
particleEffect.read(particleEffectFrame);
if (particleEffectFrame.empty()) {
particleEffect.open(particleEffectPath);
particleEffectFrameNumber = dist; // for fast start
continue;
}
else {
cv::resize(particleEffectFrame, particleEffectFrame, Size(frame.cols, frame.rows));
}
}
else {
particleEffectFrameNumber += 1;
}
if (!particleEffectFrame.empty())
cv::addWeighted(frame, 1.0, particleEffectFrame, 0.5, 0, frame, -1);
}
imshow("cam", frame);
waitKey(1);
}
return 0;
}