I am trying to detect shadows on an image with the help of many past topics but most of them either can not work too much heavy for a mobile CPU. This is the code that I built from a post which is going through each pixel and way too resource heavy.
I just want to draw contours on the image instead of removing the shadow.
The link to the post: how to detect and remove shadow of a object - OpenCV Q&A Forum
My Code:
private fun getShadowContours(
imgMat: Mat,
): Triple<List<MatOfPoint>, Mat, Mat> {
val imageShadow = imgMat.clone()
val dataRows = imageShadow.rows()
val dataCols = imageShadow.cols()
IntStream.range(5, dataRows - 5).parallel().forEach { i ->
IntStream.range(5, dataCols - 5).parallel().forEach { j ->
val pixelAddress = intArrayOf(i, j)
val pixel = imageShadow.get(pixelAddress)
val b: Int = pixel[0].toInt()
val g: Int = pixel[1].toInt()
val r: Int = pixel[2].toInt()
val varR = (r / 255.0) //RGB from 0 to 255
val varG = (g / 255.0)
val varB = (b / 255.0)
val varMin = min(min(varR, varG), varB) //Min. value of RGB
val varMax = max(max(varR, varG), varB) //Max. value of RGB
val deltaMax = varMax - varMin //Delta RGB value
var h = 0.0
var s = 0.0
if (deltaMax != 0.0) {
s = deltaMax / varMax
val deltaR = ((varMax - varR) / 6 + deltaMax / 2) / deltaMax
val deltaG = ((varMax - varG) / 6 + deltaMax / 2) / deltaMax
val deltaB = ((varMax - varB) / 6 + deltaMax / 2) / deltaMax
if (varR == varMax) {
h = deltaB - deltaG
} else if (varG == varMax) {
h =
1 / 3 + deltaR - deltaB
} else if (varB == varMax) {
h = 2 / 3 + deltaG - deltaR
}
if (h < 0.0) h += 1
if (h > 1.0) h -= 1
//if(V>0.3 && V<0.85 && H<85 && S<0.15)
//if(V>0.5 && V<0.95 && S<0.2)
if (varMax > 0.3 && varMax < 0.95 && s < 0.2) {
imageShadow.put(pixelAddress, 0.0, 0.0, 0.0, 0.0)
} else {
imageShadow.put(pixelAddress, 255.0, 255.0, 255.0, 255.0)
}
}
}
}
val imageGray = Mat()
Imgproc.cvtColor(imageShadow, imageGray, Imgproc.COLOR_RGB2GRAY)
val dilationSize = 2.0
val element = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE,
Size((2 * dilationSize + 1), (2 * dilationSize + 1)),
Point(dilationSize, dilationSize))
Imgproc.dilate(imageGray, imageGray, element)
val shadowHierarchy = Mat()
var shadowContours: List<MatOfPoint> = ArrayList()
Imgproc.findContours(imageGray,
shadowContours,
shadowHierarchy,
Imgproc.RETR_TREE,
Imgproc.CHAIN_APPROX_SIMPLE,
Point(0.0, 0.0));
val iW = imageShadow.width().toDouble()
val iH = imageShadow.height().toDouble()
shadowContours = shadowContours.parallelStream().filter {
val area = Imgproc.contourArea(it)
return@filter area > 400 && area < (iW * iH / 10.0)
}.collect(Collectors.toList())
return Triple(shadowContours, shadowHierarchy, imageShadow)
}