gocv
gocv copied to clipboard
Most Efficient Way to Scan/Access/Set gocv.Mat Values
This is a bit of a two-fold question.
Firstly, I am curious about the most performant way to access and set values in a gocv.Mat
.
Related to this first question, OpenCV has a report about the most performant way to scan images with their C++ code here: https://docs.opencv.org/2.4/doc/tutorials/core/how_to_scan_images/how_to_scan_images.html. In this report, they show that the most efficient ways to scan an image are by iterating over a pointer to each row in the image and using the built-in LUT()
function. Go doesn't allow indexing pointers to slices, and I attempted to use gocv.LUT()
in my code, and the function returns and entirely blank (black) image. So second question: I'm curious if anyone can reproduce this issue.
Thank you in advance for your help and input!
More details in the description below:
Description
Issue 1: I'm aware of and have been using gocv's .SetUCharAt()
, and it also looks like some previous discussions concluded with this as the best result. I've also seen some discussion on other sites about converting gocv.Mat
to []bytes
, accessing and manipulating the values in the byte array, then converting such back to gocv.Mat
. And lastly the official OpenCV docs (above) mention a lookup table being the most performant. Any comments on this? Is there a way to access an image a row at a time?
Issue 2: I have a 2D grayscale image, and I'm trying to remove all pixels whose occurrence count in the image is less than a given threshold. My algorithm works by 1. iterating over the image and saving the count of each pixel value in an array, 2. building the lookup table as a gocv.Mat
by iterating over the results of step 1's array and setting pixel values accordingly, and 3. replacing the values with gocv.LUT()
. I'll include my code below. The result of gocv.LUT()
is a 2D gocv.Mat
of 0s, and it should not be.
Steps to Reproduce LUT Issue
Where img
is a 2D grayscale image, threshold
is an arbitrary int, fill
is a uint8 value that will replace all values that have a count less than threshold
. In my test cases I have used 0.
// Removel al pixel values that occur less than a give threshold
// References from:
// * https://docs.opencv.org/2.4/doc/tutorials/core/how_to_scan_images/how_to_scan_images.html
func removeSmallObjects(img gocv.Mat, threshold int, fill uint8) gocv.Mat {
// Keep track of value counts
objects := [256]int{} // Default values are 0
// Iterate over image and count value occurrence
for r := 0; r < img.Rows(); r++ {
for c := 0; c < img.Cols(); c++ {
v := img.GetUCharAt(r, c)
objects[int(v)] += 1
}
}
// Create a lookup table
table := gocv.NewMatWithSize(1, 256, gocv.MatTypeCV8U)
defer table.Close()
for i, v := range objects {
if v < threshold {
table.SetUCharAt(1, i, fill) // Fill with provided value
} else {
table.SetUCharAt(1, i, uint8(i)) // Otherwise, keep the value as itself
}
}
// Remove pixels that have an occurrence count less than the provided threshold
gocv.LUT(img, table, &img)
// Return
return img
}
This is my code that calls this function:
// Convert image to gocv.Mat
imgMat, _ := gocv.ImageGrayToMatGray(gray)
defer imgMat.Close()
// Binary Inverse threshold (black background)
gocv.Threshold(imgMat, &imgMat, 127, 255, gocv.ThresholdBinaryInv)
// Remove small objects
imgClean = removeSmallObjects(imgMat, 64, uint8(0))
// imgClean ends up being the same dimension of imgMat, but made up entirely of 0s
Your Environment
- Operating System and version: Ubuntu 22.04 (Docker)
- OpenCV version used: 4.7.0
- How did you install OpenCV?
RUN git clone --depth=1 --branch v0.33.0 https://github.com/hybridgroup/gocv.git && \
cd gocv && make install
- GoCV version used: 0.33.0
- Go version: 1.20
- Did you run the
env.sh
orenv.cmd
script before trying togo run
orgo build
? No