본문 바로가기

카테고리 없음

C++ OpenCV 두 개의 동영상 또는 웹캠에 파티클 효과 주기 + 속도 조절

파티클 효과는 직접 구현해도 되지만, 보통 직접 구현보다는 이미 있는 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;
}