1 | initial version |
you need the edges of the cards to be preserved, therefore the smoothing that you are applying is not useful. Instead a sharpening algorithm should be applied. The following code works for the second image but not for the first. You need to find a sharpening kernel/solution that will help you preserve the edges.
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
cv::Mat src = cv::imread("cards.jpg");
if (!src.data)
return -1;
imshow("src", src);
// Create binary image from source image
cv::Mat bw;
cv::cvtColor(src, bw, CV_BGR2GRAY);
cv::threshold(bw, bw, 40, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
imshow("bin", bw);
// Fill holes
cv::floodFill(bw,cv::Point2i(0,0),cv::Scalar(1));
for(int i=0;i<bw.rows*bw.cols;i++)
{
if(bw.data[i]==0)
bw.data[i]=255;
}
cv::threshold(bw, bw, 40, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
imshow("filled", bw);
cv::Mat dist;
cv::distanceTransform(bw, dist, CV_DIST_L2, 3);
cv::normalize(dist, dist, 0, 1., cv::NORM_MINMAX);
imshow("Distance Transform Image", dist);
cv::threshold(dist, dist, .5, 1., CV_THRESH_BINARY);
// // Dilate a bit the dist image
// Mat kernel1 = Mat::ones(7, 7, CV_8UC1);
// dilate(dist, dist, kernel1);
// erode(dist, dist, kernel1);
// imshow("Peaks", dist);
// Create the CV_8U version of the distance image
// It is needed for cv::findContours()
cv::Mat dist_8u;
dist.convertTo(dist_8u, CV_8U);
// Find total markers
std::vector<std::vector<cv::Point> > contours;
cv::findContours(dist_8u, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
// Total objects
int ncomp = contours.size();
cv::Mat markers = cv::Mat::zeros(dist.size(), CV_32SC1);
for (int i = 0; i < ncomp; i++)
cv::drawContours(markers, contours, i, cv::Scalar::all(i+1), -1);
cv::circle(markers, cv::Point(5,5), 3, CV_RGB(255,255,255), -1);
imshow("Markers", markers*10000);
cv::watershed(src, markers);
// Generate random colors
std::vector<cv::Vec3b> colors;
for (int i = 0; i < ncomp; i++)
{
int b = cv::theRNG().uniform(0, 255);
int g = cv::theRNG().uniform(0, 255);
int r = cv::theRNG().uniform(0, 255);
colors.push_back(cv::Vec3b((uchar)b, (uchar)g, (uchar)r));
}
// Create the result image
cv::Mat dst = cv::Mat::zeros(markers.size(), CV_8UC3);
// Fill labeled objects with random colors
for (int i = 0; i < markers.rows; i++)
{
for (int j = 0; j < markers.cols; j++)
{
int index = markers.at<int>(i,j);
if (index > 0 && index <= ncomp)
dst.at<cv::Vec3b>(i,j) = colors[index-1];
else
dst.at<cv::Vec3b>(i,j) = cv::Vec3b(0,0,0);
}
}
cv::imshow("dst", dst);
cv::waitKey(0);
return 0;
}