OpenCV detect & extract text in images - c++

I am working on reading container code using an IP Camera and I came across #dhanushka's gradient based method for text detection and I've been successful with it as you can see below...
bool debugging = true;
Mat rgb = imread("/home/brian/qt/ANPR/images/0.jpg", 0);
if(debugging) { imshow("Original", rgb); }
Mat grad;
Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
morphologyEx(rgb, grad, MORPH_GRADIENT, morphKernel);
if(debugging) { imshow("gradient morph", grad); }
// binarize
Mat bw;
threshold(grad, bw, 0.0, 255.0, THRESH_BINARY | THRESH_OTSU);
if(debugging) { imshow("threshold", bw); }
// connect horizontally oriented regions
Mat connected;
morphKernel = getStructuringElement(MORPH_RECT, Size(10, 1));
morphologyEx(bw, connected, MORPH_CLOSE, morphKernel);
if(debugging) { imshow("horizontal regions morph", connected); }
// find contours
Mat mask = Mat::zeros(bw.size(), CV_8UC1);
vector<vector<Point> > contours2;
vector<Vec4i> hierarchy;
vector<Rect> txtRect;
vector<vector<Point> > txtContour;
findContours(connected, contours2, hierarchy, CV_RETR_CCOMP,
CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
// filter contours
for(int i = 0; i >= 0; i = hierarchy[i][0]) {
Rect rect = boundingRect(contours2[i]);
Mat maskROI(mask, rect);
maskROI = Scalar(0, 0, 0);
// fill the contour
drawContours(mask, contours2, i, Scalar(255, 255, 255), CV_FILLED);
// ratio of non-zero pixels in the filled region
double r = (double)countNonZero(maskROI)/(rect.width*rect.height);
/* assume at least 45% of the area is filled if it contains text */
if (r > .45 && (rect.height > 10 && rect.width > 10)) {
rectangle(rgb, rect, Scalar(0, 255, 0), 2);
txtRect.push_back(rect);
txtContour.push_back(contours2[i]);
}
}
if(debugging) { imshow("Characters", rgb); }
Mat text(rgb.size(), CV_8U, Scalar(255));
drawContours(text, txtContour, -1, Scalar(0), FILLED, 4);
if(debugging) { imshow("Detected Text", text); }
Step 0: Original Image
Step 1: Morphological gradient
Step 2: Binarized image
Step 3: Horizontally oriented regions
Step 4: Detected Text
Step 5: Extracted Text
The problem is that I have failed to properly extract the detected text so that I can use it in OCR to get the result BSIU225378.
The text I managed to extract is coming from the horizontal connected regions and its unusable for orc, is there a way I can extract text say from the binarized (threshold) image using the contours I found in the horizontal connected regions?

Related

Getting image from contour and mask

I'm getting an image from classification and it's mask using Mask RCNN.
Now I'm getting the following image
I would like to get the area around the contour as an image without the background.
//Display the label at the top of the bounding box
int baseLine;
Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
box.y = max(box.y, labelSize.height);
//rectangle(frame, Point(box.x, box.y - round(1.5 * labelSize.height)), Point(box.x + round(1.5 * labelSize.width), box.y + baseLine), Scalar(255, 255, 255), FILLED);
//putText(frame, label, Point(box.x, box.y), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0, 0, 0), 1);
// Resize the mask, threshold, color and apply it on the image
Scalar color = colors[classId % colors.size()];
// Resize the mask, threshold, color and apply it on the image
resize(objectMask, objectMask, Size(box.width, box.height));
Mat mask = (objectMask > maskThreshold);
Mat coloredRoi = (0.3 * color + 0.7 * frame(box));
coloredRoi.convertTo(coloredRoi, CV_8UC3);
// Draw the contours on the image
vector<Mat> contours;
Mat hierarchy;
mask.convertTo(mask, CV_8U);
findContours(mask, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
drawContours(coloredRoi, contours, -1, color, 5, LINE_8, hierarchy, 100);
coloredRoi.copyTo(frame(box), mask);
imshow("img", coloredRoi);
cv::waitKey(0);
this is the image showing of just the mask:
source image:

the centroid of vessels opencv

I have this image the vascular bundle
My work is to find the centroid of the blood vessels ,
I tried Image moments but I have this error message error
My code is here:
int main() {
cv::Mat img = imread("C:\\Users\\ASUS\\Desktop\\fond1.png ", CV_LOAD_IMAGE_COLOR);
Mat blue, green, red, step1, otsu, step11, green1, blue1;
Mat bgr[3]; //destination array
split(img, bgr);//split source
red.push_back(bgr[2]);
Moments mu = moments(red,true);
Point center;
center.x = mu.m10 / mu.m00;
center.y = mu.m01 / mu.m00;
circle(red, center, 2, Scalar(0, 0, 255));
imshow("Result",red);
Mat mask(red.size(), CV_8UC1, Scalar::all(0));
// Create Polygon from vertices
vector<Point> ROI_Vertices(3);
ROI_Vertices.push_back(Point(0,0 ));
ROI_Vertices.push_back(Point(center.x, center.y));
ROI_Vertices.push_back(Point(0,red.rows -1));
vector<Point> ROI_Poly;
approxPolyDP(ROI_Vertices, ROI_Poly, 1.0, true);
// Fill polygon white
fillConvexPoly(mask, &ROI_Poly[0], ROI_Poly.size(), 255, 8, 0);
Mat hide(red.size(), CV_8UC3);
red.copyTo(hide, mask);
imshow("mask", hide);
Mat blackhat,tophat,dst;
Mat element = getStructuringElement(MORPH_ELLIPSE, Size(6,6));
morphologyEx(hide, blackhat, MORPH_BLACKHAT, element);
imshow("step1", blackhat);
morphologyEx(blackhat, tophat, MORPH_TOPHAT, element);
imshow("step2", tophat);
cv::Mat r1 = cv::Mat::zeros(dst.rows, dst.cols, CV_8UC1);
tophat.copyTo(r1);
imshow("vessel", r1);
threshold(r1, dst, 9, 255, THRESH_BINARY);
// Find contours
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
///Get the moments
Mat canny_output;
// detect edges using canny
Canny(dst, canny_output, 50, 150, 3);
// find contours
findContours(canny_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
// get the moments
vector<Moments> mu(contours.size());
for (int i = 0; i<contours.size(); i++)
{
mu[i] = moments(contours[i], false);
}
// get the centroid of figures.
vector<Point2f> mc(contours.size());
for (int i = 0; i<contours.size(); i++)
{
mc[i] = Point2f(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);
}

Detect rectangles drawn on an background image using OpenCV

I’m trying to detect some rectangles (white colored) which is drawn on an image. (say using paint or some other image editing tool).
As I’m very much beginner to image processing I searched through net and OpenCV sample program to accomplish the job, but could not get it to working perfectly. I’m using OpenCV C++ library.
Algorithm that I’ve tried
cv::Mat src = cv::imread(argv[1]);
cv::Mat gray;
cv::cvtColor(src, gray, CV_BGR2GRAY);
meanStdDev(gray, mu, sigma);
cv::Mat bw;
cv::Canny(gray, bw, mu.val[0] - sigma.val[0], mu.val[0] + sigma.val[0]);
std::vector<std::vector<cv::Point> > contours;
cv::findContours(bw.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
std::vector<cv::Point> approx;
for (int i = 0; i < contours.size(); i++){
cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.02, true);
if (approx.size() >= 4 && approx.size() <= 6)
Rect boundRect = boundingRect( Mat(approx) );
rectangle( dst, boundRect.tl(), boundRect.br(), Scalar(255,255,255), 1, 8, 0 );}
Only one rectangle is detected. Can you please guide me or some link for the same.
Input image:
Output image:
I could not compile your code sample because there boundRect is declared within the if-block but rectangle drawing (trying to access boundRect) is outside of the if-block, so I adjusted your code:
int main(int argc, char* argv[])
{
cv::Mat src = cv::imread("C:/StackOverflow/Input/rectangles.png");
cv::Mat dst = src.clone();
cv::Mat gray;
cv::cvtColor(src, gray, CV_BGR2GRAY);
// ADDED: missing declaration of mu and sigma
cv::Scalar mu, sigma;
meanStdDev(gray, mu, sigma);
cv::Mat bw;
cv::Canny(gray, bw, mu.val[0] - sigma.val[0], mu.val[0] + sigma.val[0]);
// ADDED: displaying the canny output
cv::imshow("canny", bw);
std::vector<std::vector<cv::Point> > contours;
cv::findContours(bw.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
std::vector<cv::Point> approx;
for (int i = 0; i < contours.size(); i++){
cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.02, true);
if (approx.size() >= 4 && approx.size() <= 6)
{
// ADDED: brackets around both lines belonging to the if-block
cv::Rect boundRect = cv::boundingRect(cv::Mat(approx));
cv::rectangle(dst, boundRect.tl(), boundRect.br(), cv::Scalar(255, 255, 255), 3, 8, 0);
}
}
// ADDED: displaying input and results
cv::imshow("input", src);
cv::imshow("dst", dst);
cv::imwrite("C:/StackOverflow/Output/rectangles.png", dst);
cv::waitKey(0);
return 0;
}
with your input image I do get this output:
which is probably not what you expected. See the canny output image (it is always good to have a look at intermediate results for visual debugging!), there are just too many structures in the image and contours will cover all of these, so there are some that will be approximated to polynomes with 4 to 6 elements.
Instead you'll have to become a bit smarter. You could try to extract straight lines with cv::HoughLinesP and connect those lines. Or you could try to segment the image first by finding white areas (if your rectangles are always white).
int main(int argc, char* argv[])
{
cv::Mat src = cv::imread("C:/StackOverflow/Input/rectangles.png");
cv::Mat dst = src.clone();
cv::Mat gray;
cv::cvtColor(src, gray, CV_BGR2GRAY);
cv::Mat mask;
// find "white" pixel
cv::inRange(src, cv::Scalar(230, 230, 230), cv::Scalar(255, 255, 255), mask);
cv::imshow("mask", mask);
std::vector<std::vector<cv::Point> > contours;
cv::findContours(mask, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
std::vector<cv::Point> approx;
for (int i = 0; i < contours.size(); i++){
cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.02, true);
if (approx.size() >= 4 && approx.size() <= 6)
{
cv::Rect boundRect = cv::boundingRect(cv::Mat(approx));
cv::rectangle(dst, boundRect.tl(), boundRect.br(), cv::Scalar(255, 255, 255), 1, 8, 0);
}
}
cv::imshow("input", src);
cv::imshow("dst", dst);
cv::imwrite("C:/StackOverflow/Output/rectangles2.png", dst);
cv::waitKey(0);
return 0;
}
gives this result:
As you can see, there are other bright regions near white, too. The polynom approximation does not help much, too.
In general, it's easier to segment a color (even white) in HSV space. With appropriate thresholds:
inRange(hsv, Scalar(0, 0, 220), Scalar(180, 30, 255), mask);
where we don't care about the Hue, and keep only low Saturation and high Value, I get:
Then you can easily find connected components, and discard blobs smaller than a threshold th_blob_size. Resulting rectangles are (in green):
You can eventually apply other filtering stage to account for more difficult situations, but for this image removing small blobs is enough. Please post other images if you need something more robust in general.
Code:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
Mat3b img = imread("path_to_image");
int th_blob_size = 100;
Mat3b hsv;
cvtColor(img, hsv, COLOR_BGR2HSV);
Mat1b mask;
inRange(hsv, Scalar(0, 0, 220), Scalar(180, 30, 255), mask);
vector<vector<Point>> contours;
findContours(mask.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
Mat3b res = img.clone();
for (int i = 0; i < contours.size(); ++i)
{
// Remove small blobs
if (contours[i].size() < th_blob_size)
{
continue;
}
Rect box = boundingRect(contours[i]);
rectangle(res, box, Scalar(0,255,0), 1);
}
imshow("Result", res);
waitKey();
return 0;
}
Are you sure you are only finding one contour or are you only drawing one contour? It doesn't look like you are looping in the drawing routine so you will only ever draw the first one that is found.
I have a blog, long since dead, that may provide you some good direction on this: http://workingwithcomputervision.blogspot.co.uk/2012/09/game-player-step-2-finding-game-board.html
Should the link die I believe this is the most relevant part of the article which relates to drawing contours:
//Draw contours
for (int i = 0; i < contours.size(); i++) {
Scalar color = Scalar(0, 255, 0);
drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
}
I notice you are using bounding rectangles for the drawing. Here is an alternative drawing routine, again from the above link, that does this:
Rect bounds;
Mat drawing = Mat::zeros(purpleOnly.size(), CV_8UC3);
int j = 0;
for (int i = 0; i < contours.size(); i++) {
if (arcLength(contours[i], true) > 500){
Rect temp = boundingRect(contours[i]);
rectangle(drawing, temp, Scalar(255, 0, 0), 2, 8);
if (j == 0) {
bounds = temp;
} else {
bounds = bounds | temp;
}
j++;
}
}
Note that I also do some checks on the size of the contour to filter out noise.

OpenCV copy bounded text area to new image

I am new to OpenCV and I am using this code to bound the text area in image. After that I am filtering contours and putting the bounded rectangle to a vector<Rect> to copy these to new image.
Mat large = img1;
Mat rgb;
// downsample and use it for processing
pyrUp(large, rgb);
Mat small;
cvtColor(rgb, small, CV_BGR2GRAY);
// morphological gradient
Mat grad;
Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(2, 2));
morphologyEx(small, grad, MORPH_GRADIENT, morphKernel);
// binarize
Mat bw;
threshold(grad, bw, 0.0, 255.0, THRESH_BINARY | THRESH_OTSU);
// connect horizontally oriented regions
Mat connected;
//morphKernel = getStructuringElement(MORPH_RECT, Size(7, 1));
//morphologyEx(bw, connected, MORPH_CLOSE, morphKernel);
// find contours
connected = bw;
Mat mask = Mat::zeros(bw.size(), CV_8UC1);
Mat mask2;
Mat mask3;
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(connected, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
/*drawContours(mask2, contours, -1, Scalar(255), CV_FILLED);
Mat Crop(img1.rows, img1.cols, CV_8UC3);
Crop.setTo(Scalar(0, 255, 0));
img1.copyTo(Crop, mask2);
normalize(mask2.clone(), mask2, 0.0, 255.0, CV_MINMAX, CV_8UC1);
*/
vector<Rect> rect1;
int i = 0;
//filter contours
for (int idx = 0; idx >= 0; idx = hierarchy[idx][0])
{
Rect rect = boundingRect(contours[idx]);
Mat maskROI(mask, rect);
maskROI = Scalar(0, 0, 0);
// fill the contour
drawContours(mask, contours, idx, Scalar(255, 255, 255), CV_FILLED);
// ratio of non-zero pixels in the filled region
double r = (double)countNonZero(maskROI) / (rect.width*rect.height);
if (r > .45 /* assume at least 45% of the area is filled if it contains text */
&&
(rect.height > 10 && rect.width > 10 && rect.height<150 && rect.width<150) /* constraints on region size */
/* these two conditions alone are not very robust. better to use something
like the number of significant peaks in a horizontal projection as a third condition */
)
{
//making rectangles on bounded area
rectangle(rgb, rect, Scalar(0, 255, 0), 2);
//pushing bounding rectangles in vector for new mask
rect1.push_back(rect);
}
}
Input output I am getting after bounded text ares is:
After that I am using this code to copy the bounded area only to new mask
//copying bounded rectangles area from small to new mask2
for (int i = 0; i < rect1.size(); i++){
mask2 = rgb(rect1[i]);
}
but by using this I only get this last bounded text area:
How can I get or update the mask2 rows or cols to get all the mapping of bounded text areas from rgb to mask2.
That's because mask2 will be equal to the last rgb(rect1[i]) called.
You can easily solve this in two ways (using copyTo):
Create a mask (black initialized, same size as input image), where you draw (white) rectangles. Then you copy the original image to a black initialized image of the same size, using the obtained mask.
Copy each sub-image directly to a black initialized image.
Starting from this image, where the red rectangles will be your detected rectangles:
With first approach you'll get a mask like:
and, for both approaches, the final result will be:
Code for first approach:
#include <opencv2/opencv.hpp>
#include <vector>
using namespace std;
using namespace cv;
int main()
{
// Your image
Mat3b img = imread("path_to_image");
// Your rectangles
vector<Rect> rects{Rect(100, 100, 100, 200), Rect(300, 200, 200, 100), Rect(500, 400, 80, 130)};
// Mask for rectangles (black initializeds)
Mat1b mask(img.rows, img.cols, uchar(0));
Mat3b dbgRects = img.clone();
for (int i = 0; i < rects.size(); ++i)
{
// Draw white rectangles on mask
rectangle(mask, rects[i], Scalar(255), CV_FILLED);
// Show rectangles
rectangle(dbgRects, rects[i], Scalar(0, 0, 255), 2);
}
// Black initizlied result
Mat3b result(img.rows, img.cols, Vec3b(0,0,0));
img.copyTo(result, mask);
imshow("Rectangles", dbgRects);
imshow("Result", result);
waitKey();
return 0;
}
Code for second approach:
#include <opencv2/opencv.hpp>
#include <vector>
using namespace std;
using namespace cv;
int main()
{
// Your image
Mat3b img = imread("path_to_image");
// Your rectangles
vector<Rect> rects{Rect(100, 100, 100, 200), Rect(300, 200, 200, 100), Rect(500, 400, 80, 130)};
// Black initizlied result
Mat3b result(img.rows, img.cols, Vec3b(0, 0, 0));
Mat3b dbgRects = img.clone();
for (int i = 0; i < rects.size(); ++i)
{
img(rects[i]).copyTo(result(rects[i]));
// Show rectangles
rectangle(dbgRects, rects[i], Scalar(0, 0, 255), 2);
}
imshow("Rectangles", dbgRects);
imshow("Result", result);
waitKey();
return 0;
}

OpenCV Watershed segmentation miss some objects

My code is the same as this tutorial.
When I see the result image after using cv::watershed(), there is a object(upper-right) that I want to find out, but it's missing.
There are indeed six marks in image after using cv::drawContours().
Is this normal because the inaccuracy of the watershed algorithm exist?
Here is part of my code:
Mat src = imread("result01.png");
Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY);
Mat thresh;
threshold(gray, thresh, 0, 255, THRESH_BINARY | THRESH_OTSU);
// noise removal
Mat kernel = Mat::ones(3, 3, CV_8UC1);
Mat opening;
morphologyEx(thresh, opening, MORPH_OPEN, kernel, Point(-1, -1), 2);
// Perform the distance transform algorithm
Mat dist_transform;
distanceTransform(opening, dist_transform, CV_DIST_L2, 5);
// Normalize the distance image for range = {0.0, 1.0}
// so we can visualize and threshold it
normalize(dist_transform, dist_transform, 0, 1., NORM_MINMAX);
// Threshold to obtain the peaks
// This will be the markers for the foreground objects
Mat dist_thresh;
threshold(dist_transform, dist_thresh, 0.5, 1., CV_THRESH_BINARY);
Mat dist_8u;
dist_thresh.convertTo(dist_8u, CV_8U);
// Find total markers
vector<vector<Point> > contours;
findContours(dist_8u, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
// Create the marker image for the watershed algorithm
Mat markers = Mat::zeros(dist_thresh.size(), CV_32SC1);
// Draw the foreground markers
for (size_t i = 0; i < contours.size(); i++)
drawContours(markers, contours, static_cast<int>(i), Scalar::all(static_cast<int>(i)+1), -1);
// Perform the watershed algorithm
watershed(src, markers);
Original image:
Result after watershed:
You can find original, intermediate and result image here:
Result images after specific process
In your example, what you consider background is given the same label (5) as the "missing" object.
You can easily adjust this by setting a label (>0) to background, too.
You can find what is for sure background dilating and negating the thresh image.
Then, when creating a marker, you define the labels as:
0: unknown
1: background
>1 : your objects
In your output image, markers will have:
-1 : the edges between objects
0: the background (as intended by watershed)
1: the background (as you defined)
>1 : your objects.
This code should help:
#include <opencv2\opencv.hpp>
#include <vector>
using namespace std;
using namespace cv;
int main()
{
Mat3b src = imread("path_to_image");
Mat1b gray;
cvtColor(src, gray, COLOR_BGR2GRAY);
Mat1b thresh;
threshold(gray, thresh, 0, 255, THRESH_BINARY | THRESH_OTSU);
// noise removal
Mat1b kernel = getStructuringElement(MORPH_RECT, Size(3,3));
Mat1b opening;
morphologyEx(thresh, opening, MORPH_OPEN, kernel, Point(-1, -1), 2);
Mat1b kernelb = getStructuringElement(MORPH_RECT, Size(21, 21));
Mat1b background;
morphologyEx(thresh, background, MORPH_DILATE, kernelb);
background = ~background;
// Perform the distance transform algorithm
Mat1f dist_transform;
distanceTransform(opening, dist_transform, CV_DIST_L2, 5);
// Normalize the distance image for range = {0.0, 1.0}
// so we can visualize and threshold it
normalize(dist_transform, dist_transform, 0, 1., NORM_MINMAX);
// Threshold to obtain the peaks
// This will be the markers for the foreground objects
Mat1f dist_thresh;
threshold(dist_transform, dist_thresh, 0.5, 1., CV_THRESH_BINARY);
Mat1b dist_8u;
dist_thresh.convertTo(dist_8u, CV_8U);
// Find total markers
vector<vector<Point> > contours;
findContours(dist_8u, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
// Create the marker image for the watershed algorithm
Mat1i markers(dist_thresh.rows, dist_thresh.cols, int(0));
// Background as 1
Mat1i one(markers.rows, markers.cols, int(1));
bitwise_or(one, markers, markers, background);
// Draw the foreground markers (from 2 up)
for (int i = 0; i < int(contours.size()); i++)
drawContours(markers, contours, i, Scalar(i+2), -1);
// Perform the watershed algorithm
Mat3b dbg;
cvtColor(opening, dbg, COLOR_GRAY2BGR);
watershed(dbg, markers);
Mat res;
markers.convertTo(res, CV_8U);
normalize(res, res, 0, 255, NORM_MINMAX);
return 0;
}
Result:
there is very little emgu cv data on watershed.
here is my translation to this problem using c#. i know it is not the right forum but this answer kips popping up so to all the searchers:
//Mat3b src = imread("path_to_image");
//cvtColor(src, gray, COLOR_BGR2GRAY);
Image<Gray, byte> gray = smallImage.Convert<Gray, byte>();
//threshold(gray, thresh, 0, 255, THRESH_BINARY | THRESH_OTSU);
Image<Gray, byte> thresh = gray.ThresholdBinaryInv(new Gray(55), new Gray(255));
// noise removal
Mat kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), new Point(-1, -1));
//Mat1b opening;
//morphologyEx(thresh, opening, MORPH_OPEN, kernel, Point(-1, -1), 2);
Image<Gray, byte> opening = thresh.MorphologyEx(MorphOp.Open, kernel, new Point(-1, -1), 2, BorderType.Default, new MCvScalar(255));
//Mat1b kernelb = getStructuringElement(MORPH_RECT, Size(21, 21));
Mat kernel1 = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), new Point(-1, -1));
//Mat1b background;
//morphologyEx(thresh, background, MORPH_DILATE, kernelb);
Image<Gray, byte> background = thresh.MorphologyEx(MorphOp.Dilate, kernel, new Point(-1, -1), 2, BorderType.Default, new MCvScalar(255));
background = ~background;
//// Perform the distance transform algorithm
//Mat1f dist_transform;
//distanceTransform(opening, dist_transform, CV_DIST_L2, 5);
Image<Gray, float> dist_transform = new Image<Gray, float>(opening.Width, opening.Height);
CvInvoke.DistanceTransform(opening, dist_transform, null, DistType.L2, 5);
//// Normalize the distance image for range = {0.0, 1.0}
//// so we can visualize and threshold it
//normalize(dist_transform, dist_transform, 0, 1., NORM_MINMAX);
CvInvoke.Normalize(dist_transform, dist_transform, 0, 1.0, NormType.MinMax, DepthType.Default);
//// Threshold to obtain the peaks
//// This will be the markers for the foreground objects
//Mat1f dist_thresh;
//threshold(dist_transform, dist_thresh, 0.5, 1., CV_THRESH_BINARY);
Image<Gray, float> dist_thresh = new Image<Gray, float>(opening.Width, opening.Height);
CvInvoke.Threshold(dist_transform, dist_thresh, 0.5, 1.0, ThresholdType.Binary);
//Mat1b dist_8u;
//dist_thresh.convertTo(dist_8u, CV_8U);
Image<Gray, Byte> dist_8u = dist_thresh.Convert<Gray, Byte>();
//// Find total markers
//vector<vector<Point>> contours;
//findContours(dist_8u, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
CvInvoke.FindContours(dist_8u, contours, null, RetrType.External, ChainApproxMethod.ChainApproxSimple);
//// Create the marker image for the watershed algorithm
//Mat1i markers(dist_thresh.rows, dist_thresh.cols, int(0));
Image<Gray, int> markers = new Image<Gray, int>(dist_thresh.Width, dist_thresh.Height, new Gray(0));
//// Background as 1
//Mat1i one(markers.rows, markers.cols, int(1));
//bitwise_or(one, markers, markers, background);
Image<Gray, int> one = new Image<Gray, int>(markers.Cols, markers.Rows, new Gray(1));
CvInvoke.BitwiseOr(one, markers, markers, background);
//// Draw the foreground markers (from 2 up)
for (int i = 0; i < contours.Size; i++)
// drawContours(markers, contours, i, Scalar(i + 2), -1);
CvInvoke.DrawContours(markers, contours, i, new MCvScalar(i + 2));
//// Perform the watershed algorithm
//Mat3b dbg;
//cvtColor(opening, dbg, COLOR_GRAY2BGR);
//watershed(dbg, markers);
Image<Bgr, byte> dbg = new Image<Bgr, byte>(markers.Cols, markers.Rows);
CvInvoke.CvtColor(opening, dbg, ColorConversion.Gray2Bgr);
CvInvoke.Watershed(dbg, markers);
//Mat res;
//markers.convertTo(res, CV_8U);
//normalize(res, res, 0, 255, NORM_MINMAX);
CvInvoke.Normalize(markers, markers, 0, 255, NormType.MinMax);
//return 0;
to find light objects on dark background replace ThresholdBinaryInv with ThresholdBinary