Lepsze wycinanie obiektów przy kluczowaniu - chroma keying

Lepsze wycinanie obiektów przy kluczowaniu - chroma keying
Szlasi
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 2
0

Witam, muszę usunąć błędy podpróbkowania chrominancji w moim kodzie (musi być gładszy na konturach i dokładniejszy). Chcę, aby przetwarzanie maski odbywało się w funkcji errorKeying, a następnie użyte w funkcji keying, aby połączyć się z tłem i moim filmem. Napisałem kod w errorKeying, ale nie jest zbyt dokładny. Macie jakieś sugestie?
Chcę usunąć te zielone krawędzie po kluczowaniu.

Kopiuj
Mat errorKeying(Mat mask)
{
    Mat edges;
    Canny(mask, edges, 30, 70); 

    Mat blurredMask;
    GaussianBlur(mask, blurredMask, Size(0, 0), 2); 

    Mat result = mask.clone();

    int influenceSize = 10; 
    int halfInfluenceSize = influenceSize / 2;

    for (int y = 0; y < mask.rows; ++y)
    {
        for (int x = 0; x < mask.cols; ++x)
        {
            if (edges.at<uchar>(y, x) > 0) 
            {
                int startY = max(0, y - halfInfluenceSize);
                int endY = min(mask.rows - 1, y + halfInfluenceSize);
                int startX = max(0, x - halfInfluenceSize);
                int endX = min(mask.cols - 1, x + halfInfluenceSize);

                uchar value = 0;
                int count = 0;

                for (int i = startY; i <= endY; ++i)
                {
                    for (int j = startX; j <= endX; ++j)
                    {
                        if (edges.at<uchar>(i, j) > 0)
                        {
                            value += blurredMask.at<uchar>(i, j);
                            count++;
                        }
                    }
                }

                if (count > 0)
                {
                    value /= count;
                    if (value < 128)
                        result.at<uchar>(y, x) = 0; 
                    else
                        result.at<uchar>(y, x) = 255; 
                }
            }
        }
    }

    return result;
}

void keying(VideoCapture& video, Mat& img, vector<int>& col)
{
    Info();

    Mat frame, keyingFrame, hsvFrame, mask, resizedMask;

    video.read(frame);
    resize(frame, frame, Size(sizex, sizey));
    resize(img, img, frame.size(), 0, 0, INTER_CUBIC);

    Scalar lower(col[0], col[2], col[4]);
    Scalar upper(col[1], col[3], col[5]);

    cvtColor(frame, hsvFrame, COLOR_BGR2HSV);

    inRange(hsvFrame, lower, upper, mask);

    Mat smoothedMask = errorKeying(mask);

    resize(mask, resizedMask, frame.size(), 0, 0, INTER_CUBIC);

    frame.copyTo(keyingFrame);
    keyingFrame.setTo(Scalar(0, 0, 0), smoothedMask);
    bitwise_or(keyingFrame, img, keyingFrame, smoothedMask);

    imshow("Wykluczowany obraz", keyingFrame);
    imshow("Oryginalny obraz", frame);
}
MarekR22
  • Rejestracja: dni
  • Ostatnio: dni
2

Na szybkiego.
Robisz to źle bo:

  • z poziomu C++ iterujesz po pikselach - od tego jest OpenCV, żeby operacje na macierzach robić w sposób optymalny (np na karcie graficznej używając 1000 wątków, CPU tego nie potrafi). Efekt jest taki, że kod będize powolny. Staraj się używać operacji macierzowych z OpenCV.
  • algorym nie operuje na kanale alpha, więc na granicy zielonego i obiektu masz artefakty (np: połowa piksela zawiera obiekt, a druga zielony ekran). Potrzebujesz lepszego algorytmu, który stworzy kanał alpha, żeby piksele na granicy były półprzezroczyste. Z tego co wygooglałem powinieneś użyć algorytm Vlahos-a. https://smirnov-am.github.io/chromakeying/ (disclaimer nie podoba mi się kod z linku, brak linka do github też jest wskazówką, że źródło trzeba traktować ze zdrowym sceptycyzmem).

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.