OpenCV - создать маску цвета - PullRequest
0 голосов
/ 01 марта 2019

Друзья!Есть два входных изображения.Одно фоновое изображение, другое изображение маски.Мне нужно получить цветную часть маски.

Что мне нужно получить: фон , маска , изображение результата

Но я получаю что-то совершенно другое: фон , маска , изображение результата

Мой код на C #:

 //Read files
Mat img1 = CvInvoke.Imread(Environment.CurrentDirectory + "\\Test\\All1.jpg");
Mat img = CvInvoke.Imread(Environment.CurrentDirectory + "\\Test\\OriginalMask.jpg");

// Threshold and MedianBlur mask
CvInvoke.Threshold(img, img, 0, 255, Emgu.CV.CvEnum.ThresholdType.BinaryInv);
CvInvoke.MedianBlur(img, img, 13);

// without this conversion, an error appears: (mtype == CV_8U || mtype == CV_8S) && _mask.sameSize(*psrc1)
CvInvoke.CvtColor(img, img, Emgu.CV.CvEnum.ColorConversion.Rgb2Gray);

CvInvoke.BitwiseNot(img1, img1, img);

//Save file
img1.Save(Environment.CurrentDirectory + "\\Test\\Result.jpg");

Первый вопрос: Как мне достичь результата, показанного на картинке?

Второй вопрос: Почему я получаю ошибку, если я делаюне конвертировать маску: (mtype == CV_8U || mtype == CV_8S) && _mask.sameSize(*psrc1)

Третий вопрос: как сделать прозрачный фон вместо белого фона на конечном изображении?

Решение не даетдолжен быть в C #.Решение подходит для любого языка программирования, поскольку синтаксис OpenCV примерно одинаков.Заранее спасибо.

Ответы [ 3 ]

0 голосов
/ 01 марта 2019

Просто добавьте небольшую деталь к ответу HanseHirse :

Если вы добавите к маске гауссово размытие (как вы делали в своем вопросе с CvInvoke.MedianBlur(img, img, 13);), краямаски будет более плавным, и выходное изображение будет выглядеть лучше, если поместить его поверх другого изображения.

Это можно сделать, просто установив четвертый канал выходного изображения непосредственно на размытую маску.

Так что вместо

if (mask.at<uint8_t>(y, x) != 0)
            resultTransparent.at<cv::Vec4b>(y, x)[3] = 0;
        else
            resultTransparent.at<cv::Vec4b>(y, x)[3] = 255;

вы можете попробовать

resultTransparent.at<cv::Vec4b>(y, x)[3] = mask.at<uint8_t>(y, x);
0 голосов
/ 01 марта 2019

Тот же результат в Python, если он может вдохновить вас:

import cv2
import numpy as np
# Read files
img1 = cv2.imread("All1.jpg",cv2.IMREAD_COLOR);
img = cv2.imread("OriginalMask.jpg",cv2.IMREAD_GRAYSCALE)  # loading in grayscale

# Threshold and MedianBlur mask
_, img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)  # corrected to 127 instead of 0
img = cv2.medianBlur(img, 13)

# fill with white
dest= np.full(np.shape(img1),255,np.uint8)

# Assuming dst and src are of same sizes
# only copy values where the mask has color > 0
dest[img>0] = img1[img>0]  # after @T.Kau's suggestion


cv2.imshow('dest',dest)
cv2.waitKey(0)
cv2.destroyAllWindows()
0 голосов
/ 01 марта 2019

Я буду использовать C ++ в своем ответе, так как я наиболее знаком с ним.

Вот мое предложение:

// Load background as color image.
cv::Mat background = cv::imread("background.jpg", cv::IMREAD_COLOR);

// Load mask image as grayscale image.
cv::Mat mask = cv::imread("mask.jpg", cv::IMREAD_GRAYSCALE);

// Start time measurement.
auto start = std::chrono::system_clock::now();

// There are some artifacts in the JPG...
cv::threshold(mask, mask, 128, 255, cv::THRESH_BINARY);

// Initialize result image.
cv::Mat result = background.clone().setTo(cv::Scalar(255, 255, 255));

// Copy pixels from background to result image, where pixel in mask is 0.
for (int x = 0; x < background.size().width; x++)
    for (int y = 0; y < background.size().height; y++)
        if (mask.at<uint8_t>(y, x) == 0)
            result.at<cv::Vec3b>(y, x) = background.at<cv::Vec3b>(y, x);

// End time measurement.
auto end = std::chrono::system_clock::now();

// Output duration duration.
std::chrono::duration<double> elapsed_seconds = end - start;
std::cout << elapsed_seconds.count() << "\n";

// Write result.
cv::imwrite("result.png", result);

// Start time measurement.
start = std::chrono::system_clock::now();

// Generate new image with alpha channel.
cv::Mat resultTransparent = cv::Mat(result.size(), CV_8UC4);

// Copy pixels in BGR channels from result to transparent result image.
// Where pixel in mask is not 0, set alpha to 0.
for (int x = 0; x < background.size().width; x++)
{
    for (int y = 0; y < background.size().height; y++)
    {
        resultTransparent.at<cv::Vec4b>(y, x)[0] = result.at<cv::Vec3b>(y, x)[0];
        resultTransparent.at<cv::Vec4b>(y, x)[1] = result.at<cv::Vec3b>(y, x)[1];
        resultTransparent.at<cv::Vec4b>(y, x)[2] = result.at<cv::Vec3b>(y, x)[2];

        if (mask.at<uint8_t>(y, x) != 0)
            resultTransparent.at<cv::Vec4b>(y, x)[3] = 0;
        else
            resultTransparent.at<cv::Vec4b>(y, x)[3] = 255;
    }
}

// End time measurement.
end = std::chrono::system_clock::now();

// Output duration duration.
elapsed_seconds = end - start;
std::cout << elapsed_seconds.count() << "\n";

// Write transparent result.
cv::imwrite("resultTransparent.png", resultTransparent);

Результаты в этих двух выходных данных (вы не будетесм. прозрачность на втором изображении здесь на белом фоне StackOverflow):

White background

Transparent background

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...