提交 7469981d 编写于 作者: C catree

Add Java and Python code for Image Segmentation with Distance Transform and...

Add Java and Python code for Image Segmentation with Distance Transform and Watershed Algorithm tutorial. Use more Pythonic code.
上级 db48f7b5
......@@ -16,42 +16,152 @@ Theory
Code
----
@add_toggle_cpp
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp).
[here](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp).
@include samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp
@end_toggle
@add_toggle_java
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/3.4/samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java)
@include samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java
@end_toggle
@add_toggle_python
This tutorial code's is shown lines below. You can also download it from
[here](https://github.com/opencv/opencv/tree/3.4/samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py)
@include samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py
@end_toggle
Explanation / Result
--------------------
-# Load the source image and check if it is loaded without any problem, then show it:
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp load_image
![](images/source.jpeg)
- Load the source image and check if it is loaded without any problem, then show it:
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp load_image
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java load_image
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py load_image
@end_toggle
![](images/source.jpeg)
- Then if we have an image with a white background, it is good to transform it to black. This will help us to discriminate the foreground objects easier when we will apply the Distance Transform:
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp black_bg
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java black_bg
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py black_bg
@end_toggle
![](images/black_bg.jpeg)
- Afterwards we will sharpen our image in order to acute the edges of the foreground objects. We will apply a laplacian filter with a quite strong filter (an approximation of second derivative):
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp sharp
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java sharp
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py sharp
@end_toggle
![](images/laplace.jpeg)
![](images/sharp.jpeg)
- Now we transform our new sharpened source image to a grayscale and a binary one, respectively:
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp bin
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java bin
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py bin
@end_toggle
![](images/bin.jpeg)
- We are ready now to apply the Distance Transform on the binary image. Moreover, we normalize the output image in order to be able visualize and threshold the result:
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp dist
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java dist
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py dist
@end_toggle
![](images/dist_transf.jpeg)
- We threshold the *dist* image and then perform some morphology operation (i.e. dilation) in order to extract the peaks from the above image:
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp peaks
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java peaks
@end_toggle
@add_toggle_python
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py peaks
@end_toggle
![](images/peaks.jpeg)
- From each blob then we create a seed/marker for the watershed algorithm with the help of the @ref cv::findContours function:
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp seeds
@end_toggle
@add_toggle_java
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java seeds
@end_toggle
-# Then if we have an image with a white background, it is good to transform it to black. This will help us to discriminate the foreground objects easier when we will apply the Distance Transform:
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp black_bg
![](images/black_bg.jpeg)
@add_toggle_python
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py seeds
@end_toggle
-# Afterwards we will sharpen our image in order to acute the edges of the foreground objects. We will apply a laplacian filter with a quite strong filter (an approximation of second derivative):
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp sharp
![](images/laplace.jpeg)
![](images/sharp.jpeg)
![](images/markers.jpeg)
-# Now we transform our new sharpened source image to a grayscale and a binary one, respectively:
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp bin
![](images/bin.jpeg)
- Finally, we can apply the watershed algorithm, and visualize the result:
-# We are ready now to apply the Distance Transform on the binary image. Moreover, we normalize the output image in order to be able visualize and threshold the result:
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp dist
![](images/dist_transf.jpeg)
@add_toggle_cpp
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp watershed
@end_toggle
-# We threshold the *dist* image and then perform some morphology operation (i.e. dilation) in order to extract the peaks from the above image:
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp peaks
![](images/peaks.jpeg)
@add_toggle_java
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java watershed
@end_toggle
-# From each blob then we create a seed/marker for the watershed algorithm with the help of the @ref cv::findContours function:
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp seeds
![](images/markers.jpeg)
@add_toggle_python
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py watershed
@end_toggle
-# Finally, we can apply the watershed algorithm, and visualize the result:
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp watershed
![](images/final.jpeg)
\ No newline at end of file
![](images/final.jpeg)
......@@ -285,6 +285,8 @@ In this section you will learn about the image processing (manipulation) functio
- @subpage tutorial_distance_transform
*Languages:* C++, Java, Python
*Compatibility:* \> OpenCV 2.0
*Author:* Theodore Tsesmelis
......
/**
* @function Watershed_and_Distance_Transform.cpp
* @brief Sample code showing how to segment overlapping objects using Laplacian filtering, in addition to Watershed and Distance Transformation
* @author OpenCV Team
*/
......@@ -12,43 +11,47 @@
using namespace std;
using namespace cv;
int main()
int main(int argc, char *argv[])
{
//! [load_image]
//! [load_image]
// Load the image
Mat src = imread("../data/cards.png");
// Check if everything was fine
if (!src.data)
CommandLineParser parser( argc, argv, "{@input | ../data/cards.png | input image}" );
Mat src = imread( parser.get<String>( "@input" ) );
if( src.empty() )
{
cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1;
}
// Show source image
imshow("Source Image", src);
//! [load_image]
//! [load_image]
//! [black_bg]
//! [black_bg]
// Change the background from white to black, since that will help later to extract
// better results during the use of Distance Transform
for( int x = 0; x < src.rows; x++ ) {
for( int y = 0; y < src.cols; y++ ) {
if ( src.at<Vec3b>(x, y) == Vec3b(255,255,255) ) {
src.at<Vec3b>(x, y)[0] = 0;
src.at<Vec3b>(x, y)[1] = 0;
src.at<Vec3b>(x, y)[2] = 0;
}
for ( int i = 0; i < src.rows; i++ ) {
for ( int j = 0; j < src.cols; j++ ) {
if ( src.at<Vec3b>(i, j) == Vec3b(255,255,255) )
{
src.at<Vec3b>(i, j)[0] = 0;
src.at<Vec3b>(i, j)[1] = 0;
src.at<Vec3b>(i, j)[2] = 0;
}
}
}
// Show output image
imshow("Black Background Image", src);
//! [black_bg]
//! [black_bg]
//! [sharp]
// Create a kernel that we will use for accuting/sharpening our image
//! [sharp]
// Create a kernel that we will use to sharpen our image
Mat kernel = (Mat_<float>(3,3) <<
1, 1, 1,
1, -8, 1,
1, 1, 1); // an approximation of second derivative, a quite strong kernel
1, 1, 1,
1, -8, 1,
1, 1, 1); // an approximation of second derivative, a quite strong kernel
// do the laplacian filtering as it is
// well, we need to convert everything in something more deeper then CV_8U
......@@ -57,8 +60,8 @@ int main()
// BUT a 8bits unsigned int (the one we are working with) can contain values from 0 to 255
// so the possible negative number will be truncated
Mat imgLaplacian;
Mat sharp = src; // copy source image to another temporary one
filter2D(sharp, imgLaplacian, CV_32F, kernel);
filter2D(src, imgLaplacian, CV_32F, kernel);
Mat sharp;
src.convertTo(sharp, CV_32F);
Mat imgResult = sharp - imgLaplacian;
......@@ -68,41 +71,39 @@ int main()
// imshow( "Laplace Filtered Image", imgLaplacian );
imshow( "New Sharped Image", imgResult );
//! [sharp]
//! [sharp]
src = imgResult; // copy back
//! [bin]
//! [bin]
// Create binary image from source image
Mat bw;
cvtColor(src, bw, COLOR_BGR2GRAY);
cvtColor(imgResult, bw, COLOR_BGR2GRAY);
threshold(bw, bw, 40, 255, THRESH_BINARY | THRESH_OTSU);
imshow("Binary Image", bw);
//! [bin]
//! [bin]
//! [dist]
//! [dist]
// Perform the distance transform algorithm
Mat dist;
distanceTransform(bw, dist, DIST_L2, 3);
// Normalize the distance image for range = {0.0, 1.0}
// so we can visualize and threshold it
normalize(dist, dist, 0, 1., NORM_MINMAX);
normalize(dist, dist, 0, 1.0, NORM_MINMAX);
imshow("Distance Transform Image", dist);
//! [dist]
//! [dist]
//! [peaks]
//! [peaks]
// Threshold to obtain the peaks
// This will be the markers for the foreground objects
threshold(dist, dist, .4, 1., THRESH_BINARY);
threshold(dist, dist, 0.4, 1.0, THRESH_BINARY);
// Dilate a bit the dist image
Mat kernel1 = Mat::ones(3, 3, CV_8UC1);
Mat kernel1 = Mat::ones(3, 3, CV_8U);
dilate(dist, dist, kernel1);
imshow("Peaks", dist);
//! [peaks]
//! [peaks]
//! [seeds]
//! [seeds]
// Create the CV_8U version of the distance image
// It is needed for findContours()
Mat dist_8u;
......@@ -113,34 +114,36 @@ int main()
findContours(dist_8u, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
// Create the marker image for the watershed algorithm
Mat markers = Mat::zeros(dist.size(), CV_32SC1);
Mat markers = Mat::zeros(dist.size(), CV_32S);
// 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);
{
drawContours(markers, contours, static_cast<int>(i), Scalar(static_cast<int>(i)+1), -1);
}
// Draw the background marker
circle(markers, Point(5,5), 3, CV_RGB(255,255,255), -1);
circle(markers, Point(5,5), 3, Scalar(255), -1);
imshow("Markers", markers*10000);
//! [seeds]
//! [seeds]
//! [watershed]
//! [watershed]
// Perform the watershed algorithm
watershed(src, markers);
watershed(imgResult, markers);
Mat mark = Mat::zeros(markers.size(), CV_8UC1);
markers.convertTo(mark, CV_8UC1);
Mat mark;
markers.convertTo(mark, CV_8U);
bitwise_not(mark, mark);
// imshow("Markers_v2", mark); // uncomment this if you want to see how the mark
// image looks like at that point
// imshow("Markers_v2", mark); // uncomment this if you want to see how the mark
// image looks like at that point
// Generate random colors
vector<Vec3b> colors;
for (size_t i = 0; i < contours.size(); i++)
{
int b = theRNG().uniform(0, 255);
int g = theRNG().uniform(0, 255);
int r = theRNG().uniform(0, 255);
int b = theRNG().uniform(0, 256);
int g = theRNG().uniform(0, 256);
int r = theRNG().uniform(0, 256);
colors.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
}
......@@ -155,16 +158,16 @@ int main()
{
int index = markers.at<int>(i,j);
if (index > 0 && index <= static_cast<int>(contours.size()))
{
dst.at<Vec3b>(i,j) = colors[index-1];
else
dst.at<Vec3b>(i,j) = Vec3b(0,0,0);
}
}
}
// Visualize the final image
imshow("Final Result", dst);
//! [watershed]
//! [watershed]
waitKey(0);
waitKey();
return 0;
}
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
/**
*
* @brief Sample code showing how to segment overlapping objects using Laplacian filtering, in addition to Watershed
* and Distance Transformation
*
*/
class ImageSegmentation {
public void run(String[] args) {
//! [load_image]
// Load the image
String filename = args.length > 0 ? args[0] : "../data/cards.png";
Mat srcOriginal = Imgcodecs.imread(filename);
if (srcOriginal.empty()) {
System.err.println("Cannot read image: " + filename);
System.exit(0);
}
// Show source image
HighGui.imshow("Source Image", srcOriginal);
//! [load_image]
//! [black_bg]
// Change the background from white to black, since that will help later to
// extract
// better results during the use of Distance Transform
Mat src = srcOriginal.clone();
byte[] srcData = new byte[(int) (src.total() * src.channels())];
src.get(0, 0, srcData);
for (int i = 0; i < src.rows(); i++) {
for (int j = 0; j < src.cols(); j++) {
if (srcData[(i * src.cols() + j) * 3] == (byte) 255 && srcData[(i * src.cols() + j) * 3 + 1] == (byte) 255
&& srcData[(i * src.cols() + j) * 3 + 2] == (byte) 255) {
srcData[(i * src.cols() + j) * 3] = 0;
srcData[(i * src.cols() + j) * 3 + 1] = 0;
srcData[(i * src.cols() + j) * 3 + 2] = 0;
}
}
}
src.put(0, 0, srcData);
// Show output image
HighGui.imshow("Black Background Image", src);
//! [black_bg]
//! [sharp]
// Create a kernel that we will use to sharpen our image
Mat kernel = new Mat(3, 3, CvType.CV_32F);
// an approximation of second derivative, a quite strong kernel
float[] kernelData = new float[(int) (kernel.total() * kernel.channels())];
kernelData[0] = 1; kernelData[1] = 1; kernelData[2] = 1;
kernelData[3] = 1; kernelData[4] = -8; kernelData[5] = 1;
kernelData[6] = 1; kernelData[7] = 1; kernelData[8] = 1;
kernel.put(0, 0, kernelData);
// do the laplacian filtering as it is
// well, we need to convert everything in something more deeper then CV_8U
// because the kernel has some negative values,
// and we can expect in general to have a Laplacian image with negative values
// BUT a 8bits unsigned int (the one we are working with) can contain values
// from 0 to 255
// so the possible negative number will be truncated
Mat imgLaplacian = new Mat();
Imgproc.filter2D(src, imgLaplacian, CvType.CV_32F, kernel);
Mat sharp = new Mat();
src.convertTo(sharp, CvType.CV_32F);
Mat imgResult = new Mat();
Core.subtract(sharp, imgLaplacian, imgResult);
// convert back to 8bits gray scale
imgResult.convertTo(imgResult, CvType.CV_8UC3);
imgLaplacian.convertTo(imgLaplacian, CvType.CV_8UC3);
// imshow( "Laplace Filtered Image", imgLaplacian );
HighGui.imshow("New Sharped Image", imgResult);
//! [sharp]
//! [bin]
// Create binary image from source image
Mat bw = new Mat();
Imgproc.cvtColor(imgResult, bw, Imgproc.COLOR_BGR2GRAY);
Imgproc.threshold(bw, bw, 40, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);
HighGui.imshow("Binary Image", bw);
//! [bin]
//! [dist]
// Perform the distance transform algorithm
Mat dist = new Mat();
Imgproc.distanceTransform(bw, dist, Imgproc.DIST_L2, 3);
// Normalize the distance image for range = {0.0, 1.0}
// so we can visualize and threshold it
Core.normalize(dist, dist, 0, 1., Core.NORM_MINMAX);
Mat distDisplayScaled = dist.mul(dist, 255);
Mat distDisplay = new Mat();
distDisplayScaled.convertTo(distDisplay, CvType.CV_8U);
HighGui.imshow("Distance Transform Image", distDisplay);
//! [dist]
//! [peaks]
// Threshold to obtain the peaks
// This will be the markers for the foreground objects
Imgproc.threshold(dist, dist, .4, 1., Imgproc.THRESH_BINARY);
// Dilate a bit the dist image
Mat kernel1 = Mat.ones(3, 3, CvType.CV_8U);
Imgproc.dilate(dist, dist, kernel1);
Mat distDisplay2 = new Mat();
dist.convertTo(distDisplay2, CvType.CV_8U);
distDisplay2 = distDisplay2.mul(distDisplay2, 255);
HighGui.imshow("Peaks", distDisplay2);
//! [peaks]
//! [seeds]
// Create the CV_8U version of the distance image
// It is needed for findContours()
Mat dist_8u = new Mat();
dist.convertTo(dist_8u, CvType.CV_8U);
// Find total markers
List<MatOfPoint> contours = new ArrayList<>();
Mat hierarchy = new Mat();
Imgproc.findContours(dist_8u, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
// Create the marker image for the watershed algorithm
Mat markers = Mat.zeros(dist.size(), CvType.CV_32S);
// Draw the foreground markers
for (int i = 0; i < contours.size(); i++) {
Imgproc.drawContours(markers, contours, i, new Scalar(i + 1), -1);
}
// Draw the background marker
Imgproc.circle(markers, new Point(5, 5), 3, new Scalar(255, 255, 255), -1);
Mat markersScaled = markers.mul(markers, 10000);
Mat markersDisplay = new Mat();
markersScaled.convertTo(markersDisplay, CvType.CV_8U);
HighGui.imshow("Markers", markersDisplay);
//! [seeds]
//! [watershed]
// Perform the watershed algorithm
Imgproc.watershed(imgResult, markers);
Mat mark = Mat.zeros(markers.size(), CvType.CV_8U);
markers.convertTo(mark, CvType.CV_8UC1);
Core.bitwise_not(mark, mark);
// imshow("Markers_v2", mark); // uncomment this if you want to see how the mark
// image looks like at that point
// Generate random colors
Random rng = new Random(12345);
List<Scalar> colors = new ArrayList<>(contours.size());
for (int i = 0; i < contours.size(); i++) {
int b = rng.nextInt(256);
int g = rng.nextInt(256);
int r = rng.nextInt(256);
colors.add(new Scalar(b, g, r));
}
// Create the result image
Mat dst = Mat.zeros(markers.size(), CvType.CV_8UC3);
byte[] dstData = new byte[(int) (dst.total() * dst.channels())];
dst.get(0, 0, dstData);
// Fill labeled objects with random colors
int[] markersData = new int[(int) (markers.total() * markers.channels())];
markers.get(0, 0, markersData);
for (int i = 0; i < markers.rows(); i++) {
for (int j = 0; j < markers.cols(); j++) {
int index = markersData[i * markers.cols() + j];
if (index > 0 && index <= contours.size()) {
dstData[(i * dst.cols() + j) * 3 + 0] = (byte) colors.get(index - 1).val[0];
dstData[(i * dst.cols() + j) * 3 + 1] = (byte) colors.get(index - 1).val[1];
dstData[(i * dst.cols() + j) * 3 + 2] = (byte) colors.get(index - 1).val[2];
} else {
dstData[(i * dst.cols() + j) * 3 + 0] = 0;
dstData[(i * dst.cols() + j) * 3 + 1] = 0;
dstData[(i * dst.cols() + j) * 3 + 2] = 0;
}
}
}
dst.put(0, 0, dstData);
// Visualize the final image
HighGui.imshow("Final Result", dst);
//! [watershed]
HighGui.waitKey();
System.exit(0);
}
}
public class ImageSegmentationDemo {
public static void main(String[] args) {
// Load the native OpenCV library
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
new ImageSegmentation().run(args);
}
}
from __future__ import print_function
import cv2 as cv
import numpy as np
import argparse
import random as rng
rng.seed(12345)
## [load_image]
# Load the image
parser = argparse.ArgumentParser(description='Code for Image Segmentation with Distance Transform and Watershed Algorithm.\
Sample code showing how to segment overlapping objects using Laplacian filtering, \
in addition to Watershed and Distance Transformation')
parser.add_argument('--input', help='Path to input image.', default='../data/cards.png')
args = parser.parse_args()
src = cv.imread(args.input)
if src is None:
print('Could not open or find the image:', args.input)
exit(0)
# Show source image
cv.imshow('Source Image', src)
## [load_image]
## [black_bg]
# Change the background from white to black, since that will help later to extract
# better results during the use of Distance Transform
src[np.all(src == 255, axis=2)] = 0
# Show output image
cv.imshow('Black Background Image', src)
## [black_bg]
## [sharp]
# Create a kernel that we will use to sharpen our image
# an approximation of second derivative, a quite strong kernel
kernel = np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]], dtype=np.float32)
# do the laplacian filtering as it is
# well, we need to convert everything in something more deeper then CV_8U
# because the kernel has some negative values,
# and we can expect in general to have a Laplacian image with negative values
# BUT a 8bits unsigned int (the one we are working with) can contain values from 0 to 255
# so the possible negative number will be truncated
imgLaplacian = cv.filter2D(src, cv.CV_32F, kernel)
sharp = np.float32(src)
imgResult = sharp - imgLaplacian
# convert back to 8bits gray scale
imgResult = np.clip(imgResult, 0, 255)
imgResult = imgResult.astype('uint8')
imgLaplacian = np.clip(imgLaplacian, 0, 255)
imgLaplacian = np.uint8(imgLaplacian)
#cv.imshow('Laplace Filtered Image', imgLaplacian)
cv.imshow('New Sharped Image', imgResult)
## [sharp]
## [bin]
# Create binary image from source image
bw = cv.cvtColor(imgResult, cv.COLOR_BGR2GRAY)
_, bw = cv.threshold(bw, 40, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
cv.imshow('Binary Image', bw)
## [bin]
## [dist]
# Perform the distance transform algorithm
dist = cv.distanceTransform(bw, cv.DIST_L2, 3)
# Normalize the distance image for range = {0.0, 1.0}
# so we can visualize and threshold it
cv.normalize(dist, dist, 0, 1.0, cv.NORM_MINMAX)
cv.imshow('Distance Transform Image', dist)
## [dist]
## [peaks]
# Threshold to obtain the peaks
# This will be the markers for the foreground objects
_, dist = cv.threshold(dist, 0.4, 1.0, cv.THRESH_BINARY)
# Dilate a bit the dist image
kernel1 = np.ones((3,3), dtype=np.uint8)
dist = cv.dilate(dist, kernel1)
cv.imshow('Peaks', dist)
## [peaks]
## [seeds]
# Create the CV_8U version of the distance image
# It is needed for findContours()
dist_8u = dist.astype('uint8')
# Find total markers
_, contours, _ = cv.findContours(dist_8u, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
# Create the marker image for the watershed algorithm
markers = np.zeros(dist.shape, dtype=np.int32)
# Draw the foreground markers
for i in range(len(contours)):
cv.drawContours(markers, contours, i, (i+1), -1)
# Draw the background marker
cv.circle(markers, (5,5), 3, (255,255,255), -1)
cv.imshow('Markers', markers*10000)
## [seeds]
## [watershed]
# Perform the watershed algorithm
cv.watershed(imgResult, markers)
#mark = np.zeros(markers.shape, dtype=np.uint8)
mark = markers.astype('uint8')
mark = cv.bitwise_not(mark)
# uncomment this if you want to see how the mark
# image looks like at that point
#cv.imshow('Markers_v2', mark)
# Generate random colors
colors = []
for contour in contours:
colors.append((rng.randint(0,256), rng.randint(0,256), rng.randint(0,256)))
# Create the result image
dst = np.zeros((markers.shape[0], markers.shape[1], 3), dtype=np.uint8)
# Fill labeled objects with random colors
for i in range(markers.shape[0]):
for j in range(markers.shape[1]):
index = markers[i,j]
if index > 0 and index <= len(contours):
dst[i,j,:] = colors[index-1]
# Visualize the final image
cv.imshow('Final Result', dst)
## [watershed]
cv.waitKey()
......@@ -28,10 +28,9 @@ knn_matches = matcher.knnMatch(descriptors1, descriptors2, 2)
#-- Filter matches using the Lowe's ratio test
ratio_thresh = 0.7
good_matches = []
for matches in knn_matches:
if len(matches) > 1:
if matches[0].distance / matches[1].distance <= ratio_thresh:
good_matches.append(matches[0])
for m,n in knn_matches:
if m.distance / n.distance <= ratio_thresh:
good_matches.append(m)
#-- Draw matches
img_matches = np.empty((max(img1.shape[0], img2.shape[0]), img1.shape[1]+img2.shape[1], 3), dtype=np.uint8)
......
......@@ -28,10 +28,9 @@ knn_matches = matcher.knnMatch(descriptors_obj, descriptors_scene, 2)
#-- Filter matches using the Lowe's ratio test
ratio_thresh = 0.75
good_matches = []
for matches in knn_matches:
if len(matches) > 1:
if matches[0].distance / matches[1].distance <= ratio_thresh:
good_matches.append(matches[0])
for m,n in knn_matches:
if m.distance / n.distance <= ratio_thresh:
good_matches.append(m)
#-- Draw matches
img_matches = np.empty((max(img_object.shape[0], img_scene.shape[0]), img_object.shape[1]+img_scene.shape[1], 3), dtype=np.uint8)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册