gocv
gocv copied to clipboard
How to get and set pixel color to Mat?
Description
In OpenCV you can get and set pixel values in the following manner.
Mat image = img;
for(int y=0; y<img.rows; y++)
{
for(int x=0; x<img.cols; x++)
{
// get pixel
Vec3b color = image.at<Vec3b>(Point(x,y));
// ... do something to the color ....
// set pixel
image.at<Vec3b>(Point(x,y)) = color;
}
}
How can i do something similar in gocv? One way i have tried is using the SetTo
method and providing a scalar as parameter, but there is no way i can tell with this method which pixel value i want to update, something like SetTo(x, y, sclarValue)
. Is there something i'm missing? I'm afraid iterating over the image pixels and updating the underneath matrix will update only the last iteration.
I found a hacky solution but i'm not really sure if this is the way to go. First i'm converting the matrix to bytes, then i'm updating the pixel values directly on databyte level and finally creating a new Mat
from bytes with gocv.NewMatFromBytes
.
In code this is how it should look like:
data := mat.ToBytes()
for x := 0; x < cols; x++ {
for y := 0; y < rows; y++ {
// Obtain some values from Sobel matrix.
u := gradX.GetVecfAt(x, y)
v := gradY.GetVecfAt(x, y)
// Update the pixel values
idx := x*cols*ch + y*ch
data[idx+0] = byte(u[0])
data[idx+1] = byte(v[0])
data[idx+2] = 0.0
data[idx+3] = 0.0
}
}
nm, err := gocv.NewMatFromBytes(rows, cols, gocv.MatChannels3, data)
if err != nil {
log.Fatalf("Cannot create new Mat from bytes: %v", err)
}
@deadprogram Please take a look and show me what do you think?
@esimov Did you found the answer for this?I also get pixel color of Mat!
@ibenben I think the solution posted above will just work.
u := gradX.GetVecfAt(x, y) Is this the way to get pixel color?Which is gradX? @esimov
idx := xcolsch + y*ch
The index is this,I knew it.Thanks.
@ibenben gradX is a Mat. gradX.GetVecfAt(x, y)
will return a vector of floats, but if you need the pixel values you can just use GetIntAt
. I'm using GetVecfAt(x, y)
because of my specific needs.
Did I do the right thing? @esimov
You need to take care about the channel length. It might be possible that the channel length is not 3. Otherwise the code looks good, but you need to make some operations with the obtained pixels, otherwise you are only making a data byte copy.
@esimov Thanks!
Personally, I use self-writed type for uchar based on gocv.Veci approach. I think you can use same logic on any type.
type Vecb []uint8
func GetVecbAt(m gocv.Mat, row int, col int) Vecb {
ch := m.Channels()
v := make(Vecb, ch)
for c := 0; c < ch; c++ {
v[c] = m.GetUCharAt(row, col*ch+c)
}
return v
}
func (v Vecb) SetVecbAt(m gocv.Mat, row int, col int) {
ch := m.Channels()
for c := 0; c < ch; c++ {
m.SetUCharAt(row, col*ch+c, v[c])
}
}
Although, you shouldn't use SetVecbAt function on Mat, that has different channel count
This worked for me:
// img is of type Mat
colorRed := gocv.NewScalar(0,0,255,0) // B, G, R and alpha
img.SetTo(color)
... all pixels are set to RED ... Let's draw a red 100x200 pixels rectangle (RGB image):
img := gocv.NewMatWithSize(200,100, gocv.MatTypeCV8UC3)
img.SetTo(gocv.NewScalar(0,0,255,0))
gocv.IMWrite("/tmp/rectangle.jpg",img)