I am creating an program to automatically separate the solar cells of from a pv module for which i first thresholded the image using adaptive threshold to obtain the following image
After which i intend to remove the the black pixels within the cell boundries by using dilation for which i have used a elliptical structuring element of size (10,10) and have obtained the following image
As you can see there are still some black pixels left, now if i increase the size of the structuring element i lose the cell boundaries
I have tried the other structuring elements available such as cross and rectangular without any success hence i would need to define a custom kernel and don't have an idea about how do i go about defining one.
import numpy as np
import cv2
img=cv2.imread('result2.jpg',0)
th1 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
cv2.THRESH_BINARY,25,-2)
kernel=cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(15,15))
closing = cv2.morphologyEx(th1, cv2.MORPH_CLOSE, kernel)
cv2.imwrite('closing.jpg',closing)
cv2.imwrite('threshold.jpg',th1)
cv2.waitKey(0)
cv2.destroyAllWindows()
My first piece of advice is to not threshold right away. Thresholding is something you want to do way at the end. Thresholding throws away valuable information. Morphological operations work on grey-value images too!
Choosing the right morphological operators to keep only the shapes you are interested in is actually quite intuitive. In this case, you want to keep both horizontal and vertical lines. Let's use line structuring elements. The lines are dark, so we use a closing to remove things that do not look like our lines.
A closing with vertical lines will remove all horizontal lines, and a closing with horizontal lines will remove all vertical lines. So how to combine these two? It turns out that the infimum (pixel-wise minimum) of two closings is a closing also. So the infimum of a closing with vertical lines and one with horizontal lines is a closing with the two lines at the same time, you'll preserve shapes where either of those two lines fit.
Here is an example. I'm using PyDIP (I don't have OpenCV).
import diplib as dip
img = dip.ImageRead('/Users/cris/Downloads/ZrF7k.tif')
img = img.TensorElement(1) # keep only green channel
img = img[0:-2,1:-1] # let's remove the artifacts at the right and top edges
f1 = dip.Closing(img, dip.SE([50,1],'rectangular'))
f2 = dip.Closing(img, dip.SE([1,50],'rectangular'))
out = dip.Infimum(f1, f2)
out.Show('lin')
You can try to tweak that a bit, and add some additional processing, and add your adaptive thresholding at the end to get the edges of the PV cells. But there is actually a much better way of finding these.
I'm taking advantage here of the fact that the panel is so very straight w.r.t. the image, and that it covers the whole image. We can simply take a mean projection along rows and along columns:
x = dip.Mean(out, process=[1, 0]).Squeeze()
y = dip.Mean(out, process=[0, 1]).Squeeze()
import matplotlib.pyplot as pp
pp.subplot(2,1,1)
pp.plot(x)
pp.subplot(2,1,2)
pp.plot(y)
pp.show()
It should be fairly straight-forward to detect the edges of the cells from these projections.