3

So I have a picture of a sand dune that looks currently like this.enter image description here

What I'm trying to do is identify the ripples within the picture using opencv in Python. I'm just learning this library so I don't know all the quirks within the library. I did some research, but couldn't find a problem similar to this one, this one is especially difficult because of the shadows that are created from the ripples. My expected outcome should be somewhat the inverse of this, making all the ripples standing out more than the other features. Below is a picture of a man with his hair as the feature that stands out. I want to do the same thing with the ripples in the dune below.

image here The following code is what I have beneath and this is the output of my final product, but still needs some work.

 path = "C:/some path//to get//to my picture//Dune field_resize.jpg"


# image I'm using
img = cv2.imread ( path , cv2.IMREAD_GRAYSCALE )
kernel = np.ones ( (5 , 5) , np.uint8 )

# Canny edge detecting
edges = cv2.Canny ( img , 75 , 200 )
th , img = cv2.threshold ( img , 220 , 255 , cv2.THRESH_BINARY_INV );

# Copy the thresholded image.
img_floodfill = img.copy ()

# Mask used to flood filling.
# Notice the size needs to be 2 pixels than the image.
h , w = img.shape[:2]
mask = np.zeros ( (h + 2 , w + 2) , np.uint8 )

# Floodfill from point (0, 0)
cv2.floodFill ( img_floodfill , mask , (0 , 0) , 255 );

# Invert floodfilled image
img_floodfill_inv = cv2.bitwise_not ( img_floodfill )

# Combine the two images to get the foreground.
img_out = img | img_floodfill_inv

# Display images.
cv2.imwrite ( "Thresholded Image.png" , img )
cv2.imwrite ( "Floodfilled Image.png" , img_floodfill )
cv2.imwrite ( "Inverted Floodfilled Image.png" , img_floodfill_inv )
cv2.imwrite ( "Foreground.png" , img )
cv2.waitKey ( 0 )

cv2.imwrite ( "canny_edge.png" , edges )

img_erosion = cv2.erode ( img , kernel , iterations=1 )

cv2.waitKey ( 0 )
cv2.destroyAllWindows ()

enter image here

nathancy
  • 42,661
  • 14
  • 115
  • 137
Alex
  • 211
  • 1
  • 11
  • This is an interesting problem. However, it is not very clear what is the expected output. Can you please edit your question with more details about the result you expect? – Paul92 May 03 '19 at 19:50
  • Just added some more detail, hopefully it makes a little bit more sense. – Alex May 03 '19 at 20:19
  • You seem to be detecting the shadows. What about inverting your result? – Paul92 May 03 '19 at 20:37
  • I agree, it would be helpful if you could post something, even a sketch, that shows the sort of output you'd like. If you can't, then I suggest looking at Haralick textures (and there are other texture attributes). If you're open to an entirely different approach, then you should know that a lot of people are attacking problems like this with deep learning now (e.g. U-Net for image segmentation problems, which this seems like). But that will need training data... – Matt Hall May 03 '19 at 20:41

1 Answers1

3

Here is a simple approach using some filtering

  • Convert image to grayscale
  • Use canny edge detection to find edges
  • Find contours
  • For each contour find its area and filter using a maximum threshold area

Canny

enter image description here

Detected ripples

enter image description here

You may need to adjust the cv2.Canny or threshold area parameters. Another possible approach to filtering after Canny detection would be to distinguish between straight and irregular lines. There are probably better filtering methods but this simple area approach gets most of the ripples.

import cv2
import numpy as np

original_image = cv2.imread('1.jpg')
gray = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY)

canny = cv2.Canny(gray, 50, 150)
cnts = cv2.findContours(canny.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

threshold_max_area = 165
for c in cnts:
    area = cv2.contourArea(c)
    if area < threshold_max_area:
        cv2.drawContours(original_image,[c], 0, (0,255,0), 1)

cv2.imshow('canny', canny)
cv2.imshow('found', original_image)

cv2.waitKey(0)
cv2.destroyAllWindows()
nathancy
  • 42,661
  • 14
  • 115
  • 137