personas - reconocimiento de objetos opencv python
sustracción de fondo opencv (2)
Creo que cuando lo hago así obtengo los resultados correctos: (en el espacio de color YCrCb) pero el acceso a cada px es lento, así que necesito encontrar otro algoritmo
cv::Mat mask(image.rows, image.cols, CV_8U, cv::Scalar(0,0,0));
cv::Mat_<cv::Vec3b>::const_iterator itImage= image.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::const_iterator itend= image.end<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::iterator itRef= refRoi.begin<cv::Vec3b>();
cv::Mat_<uchar>::iterator itMask= mask.begin<uchar>();
for ( ; itImage!= itend; ++itImage, ++itRef, ++itMask) {
int distance = abs((*itImage)[0]-(*itRef)[0])+
abs((*itImage)[1]-(*itRef)[1])+
abs((*itImage)[2]-(*itRef)[2]);
if(distance < 30)
*itMask = 0;
else
*itMask = 255;
}
Tengo una imagen de la escena de fondo y una imagen de la misma escena con objetos en el frente. Ahora quiero crear una máscara del objeto en primer plano con sustracción de fondo. Ambas imágenes son RGB.
Ya creé el siguiente código:
cv::Mat diff;
diff.create(orgImage.dims, orgImage.size, CV_8UC3);
diff = abs(orgImage-refImage);
cv::Mat mask(diff.rows, diff.cols, CV_8U, cv::Scalar(0,0,0));
//mask = (diff > 10);
for (int j=0; j<diff.rows; j++) {
// get the address of row j
//uchar* dataIn= diff.ptr<uchar>(j);
//uchar* dataOut= mask.ptr<uchar>(j);
for (int i=0; i<diff.cols; i++) {
if(diff.at<cv::Vec3b>(j,i)[0] > 30 || diff.at<cv::Vec3b>(j,i)[1] > 30 || diff.at<cv::Vec3b>(j,i)[2] > 30)
mask.at<uchar>(j,i) = 255;
}
}
No sé si estoy haciendo esto bien?
Eche un vistazo a la función inRange de OpenCV. Esto le permitirá establecer múltiples umbrales al mismo tiempo para una imagen de 3 canales.
Entonces, para crear la máscara que estabas buscando, haz lo siguiente:
inRange(diff, Scalar(30, 30, 30), Scalar(255, 255, 255), mask);
Esto también debería ser más rápido que tratar de acceder a cada píxel usted mismo.
EDITAR: Si lo que intentas hacer es detectar la piel, primero haría la detección de la piel, y luego haré una resta de fondo para eliminar el fondo. De lo contrario, su detector de piel tendrá que tener en cuenta el cambio de intensidad causado por la resta.
Vea mi otra respuesta , sobre buenas técnicas para la detección de la piel.
EDITAR:
¿Esto es más rápido?
int main(int argc, char* argv[])
{
Mat fg = imread("fg.jpg");
Mat bg = imread("bg.jpg");
cvtColor(fg, fg, CV_RGB2YCrCb);
cvtColor(bg, bg, CV_RGB2YCrCb);
Mat distance = Mat::zeros(fg.size(), CV_32F);
vector<Mat> fgChannels;
split(fg, fgChannels);
vector<Mat> bgChannels;
split(bg, bgChannels);
for(size_t i = 0; i < fgChannels.size(); i++)
{
Mat temp = abs(fgChannels[i] - bgChannels[i]);
temp.convertTo(temp, CV_32F);
distance = distance + temp;
}
Mat mask;
threshold(distance, mask, 35, 255, THRESH_BINARY);
Mat kernel5x5 = getStructuringElement(MORPH_RECT, Size(5, 5));
morphologyEx(mask, mask, MORPH_OPEN, kernel5x5);
imshow("fg", fg);
imshow("bg", bg);
imshow("mask", mask);
waitKey();
return 0;
}
Este código produce esta máscara en función de tus imágenes de entrada:
Finalmente, esto es lo que obtengo usando mi método de umbralización simple:
Mat diff = fgYcc - bgYcc;
vector<Mat> diffChannels;
split(diff, diffChannels);
// only operating on luminance for background subtraction...
threshold(diffChannels[0], bgfgMask, 1, 255.0, THRESH_BINARY_INV);
Mat kernel5x5 = getStructuringElement(MORPH_RECT, Size(5, 5));
morphologyEx(bgfgMask, bgfgMask, MORPH_OPEN, kernel5x5);
Esto produce la siguiente máscara: