Ask Your Question
1

How to remove green color i.e. to set it to 0 in an image?

asked 2016-08-20 04:08:08 -0500

riya1405 gravatar image

updated 2016-08-21 03:50:18 -0500

I am having an image and wish to remove the green color in it i.e. to set it to value 0. How to do that? https://dditec.miraheze.org/wiki/File...

edit retag flag offensive close merge delete

Comments

can you be more specific, on what you really want ? do you want to remove the green channel entirely ? do you want to remove "pure" green only ? or "some shade" of it ? what is your input ?

berak gravatar imageberak ( 2016-08-20 05:56:31 -0500 )edit

if it is pure green ..how to do that without for loop pixel accessing ..is there anyway..@berak..i just want to know that logic

Venky009 gravatar imageVenky009 ( 2016-08-20 06:02:10 -0500 )edit

I dont want to remove green channel. That would give me some sort of pinkish image. I need to remove green from the entire image. The original image with green turned to black in it. The input is image containing trees and bushes. And i wish to set the regions as black.

riya1405 gravatar imageriya1405 ( 2016-08-20 07:32:17 -0500 )edit

an example image would be helpful, now.

berak gravatar imageberak ( 2016-08-20 07:53:43 -0500 )edit

Yeah, I'll add the image

riya1405 gravatar imageriya1405 ( 2016-08-21 03:29:19 -0500 )edit

Is that process still called blitting in the world of CV & DIP?

j0h gravatar imagej0h ( 2016-08-22 09:19:13 -0500 )edit

4 answers

Sort by ยป oldest newest most voted
5

answered 2016-08-22 08:44:03 -0500

berak gravatar image

imho, inRange() on a hsv image will already get you quite far.

some tricks to improve:

  • blur. as much as you can.
  • try to sample as many green spots in the images, as you can, then build your range based on mean/stdev of those:


#include "opencv2/opencv.hpp"
#include <iostream>
using namespace cv;
using namespace std;

Mat im_hsv, dist;
void pick_color(int e, int x, int y, int s, void *)
{
    if (e==1)
    {
        int r = 3;
        int off[9*2] = {0,0, -r,-r, -r,0, -r,r, 0,r, r,r, r,0, r,-r, 0,-r};
        for (int i=0; i<9; i++)
        {
            Vec3b p = im_hsv.at<Vec3b>(y+off[2*i], x+off[2*i+1]);
            cerr << int(p[0]) << " " << int(p[1]) << " " << int(p[2]) << endl;
            dist.push_back(p);
        }
    }
}

int main( int argc, char** argv )
{
    namedWindow("blue");
    setMouseCallback("blue", pick_color);

    String c_in = "."; // check a whole folder.
    if (argc>1) c_in = argv[1]; // or an image
    vector<String> fn;
    glob(c_in, fn, true);
    for(size_t i=0; i<fn.size(); i++)
    {
        Mat im_bgr = imread(fn[i]);
        if (im_bgr.empty()) continue;
        cvtColor(im_bgr, im_hsv, COLOR_BGR2HSV);
        imshow("blue", im_bgr);
        int k = waitKey() & 0xff;
        if (k==27) break; // esc.
    }
    Scalar m,v;
    meanStdDev(dist,m,v);
    cerr << "mean, var: " << endl;
    cerr << m[0] << " " << m[1] << " " << m[2] << " " << v[0] << " " << v[1] << " " << v[2] << endl;
    return 0;
}

i got values, similar to this:

[29.1045 100.815 64.5172] [6.03475 36.778 19.7858]

later, you can build a range from mean and stddev:

Scalar lo(m[0]-v[0], m[1]-v[1], m[2]-v[2]); // mean-var for low
Scalar hi(m[0]+v[0], m[1]+v[1], m[2]+v[2]); // mean + var for high

cvtColor(im_bgr, im_hsv, COLOR_BGR2HSV);
blur(im_hsv, im_hsv, Size(8,8));

Mat mask;
inRange(im_hsv, lo, hi, mask);
im_bgr.setTo(Scalar(0,255,255), mask); // i used yellow, to make it more visible..

image description

edit flag offensive delete link more

Comments

1

btw, good luck with your drone project !

berak gravatar imageberak ( 2016-08-22 08:47:28 -0500 )edit

Thank you! And i just wanted to ask that what is the equivalent of setTo() in python?

riya1405 gravatar imageriya1405 ( 2016-08-22 08:51:42 -0500 )edit

unfortunately there is no direct equivalent (that would take a mask) in python. you'll probablyhave to find a way using binary ops in numpy.

actually, it's the same prob as here , no ?

berak gravatar imageberak ( 2016-08-22 08:57:58 -0500 )edit

i found this in the always helful python tutorials ;)

berak gravatar imageberak ( 2016-08-22 09:35:37 -0500 )edit

Thanks a lot!

riya1405 gravatar imageriya1405 ( 2016-08-22 10:38:35 -0500 )edit

let's hope, you're not the only "working" person in your team ..

berak gravatar imageberak ( 2016-08-22 10:43:44 -0500 )edit

Others are working too I think ;)

riya1405 gravatar imageriya1405 ( 2016-08-22 11:21:28 -0500 )edit
0

answered 2016-08-20 05:59:11 -0500

updated 2016-08-20 06:23:28 -0500

berak gravatar image

You could try to use split and merge: Split/Merge

split your image, call setTo(0) for your green channel and merge them again.

edit flag offensive delete link more
0

answered 2016-08-20 11:39:18 -0500

updated 2016-08-20 11:46:03 -0500

as @berak said : "you'd transfer to HSV, specify a range for "green" there, and use inRange() to get a mask for that color. then you can use img.setTo(0, mask)"

take a look at the code below. also see this post

#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{

    Mat image = imread("Simple_RGB_color_wheel.png");

    if (image.empty())
    {
        cout << endl
             << "ERROR! Unable to read the image" << endl
             << "Press a key to terminate";
        cin.get();
        return 0;
    }
    imshow("source",image);

    Mat hsv,mask;

    cvtColor(image,hsv,COLOR_BGR2HSV);
    inRange(hsv,Scalar(30,0,0),Scalar(90,255,255),mask);
    //inRange(hsv,Scalar(40,0,0),Scalar(80,255,255),mask);

    image.setTo(Scalar(0,0,0),mask);

    imshow("result",image);
    waitKey();

    return 0;
}

input image:

source_image

output image: (inRange(hsv,Scalar(30,0,0),Scalar(90,255,255),mask);)

image description

output image: (inRange(hsv,Scalar(40,0,0),Scalar(80,255,255),mask);)

image description

edit flag offensive delete link more

Comments

@sturkmen, unrelated to the question, but your answer went through the moderation queue here.

makes me think: what? again, it's all about "the moderation queue". shouldn't approved users with karma > X get spared of this ?

berak gravatar imageberak ( 2016-08-20 13:07:35 -0500 )edit

maybe the external link causes to went through the moderation queue.

sturkmen gravatar imagesturkmen ( 2016-08-20 13:29:15 -0500 )edit

just let me add a reminder, that above images show Hue in the [0..360] range, while in opencv it is [0..180]

berak gravatar imageberak ( 2016-08-22 07:34:06 -0500 )edit
-1

answered 2016-08-20 05:41:22 -0500

Venky009 gravatar image

updated 2016-08-20 05:54:23 -0500

load the img into mat ..read the r g b s pixel wise ..and use the condition if (r == 0 && g == 255 && b == 0) to make that pixel to 0..You can change the logic according to ur img intensities.

{;

cv::Mat img = cv::imread("inputPath");//3channel imagepath;

byte* img_ptr = (byte*)img.data;
int r, g, b;
for (int y = 0; y < img.rows; y++)
{
    for (int x = 0; x < img.cols; x++)
    {
        r = img_ptr[x * 3 + 2 + y*img.cols * 3];
        g = img_ptr[x * 3 + 1 + y*img.cols * 3];
        b = img_ptr[x * 3 + 0 + y*img.cols * 3];

        if (r == 0 && g == 255 && b == 0)
        {
            img_ptr[x * 3 + 2 + y*img.cols * 3]=0;
            img_ptr[x * 3 + 1 + y*img.cols * 3]=0;
            img_ptr[x * 3 + 0 + y*img.cols * 3]=0;
        }
    }
}
cv::imwrite("outputPath", img);
img.release();

}

edit flag offensive delete link more

Comments

sorry for the downvote. , but this is all a terrible idea:

  • never write per-pixel loops in opencv, please. your idea does not handle padding, rois, or anything that leads to non-continuous memory.
  • you got the indexing wrong(out of sloppyness), so your r==g==b (also note, that it's bgr order in opencv)
berak gravatar imageberak ( 2016-08-20 05:52:36 -0500 )edit

its ok bro..but how to access the pixel without for loop

Venky009 gravatar imageVenky009 ( 2016-08-20 05:55:16 -0500 )edit

see e.g. @FooBar's idea above. (that would "remove the green channel")

to remove "shades", you'd transfer to HSV, specify a range for "green" there, and use inRange() to get a mask for that color. then you can use img.setTo(0, mask);

berak gravatar imageberak ( 2016-08-20 06:10:26 -0500 )edit

honestly, would you have found the indexing problem on your own ? there's a ton of reasons to avoid this horrific approach entirely. again, opencv is a highlevel matrix lib, don't try such dumb and slow things. (worse even, you're trying to sell that to another noob !)

berak gravatar imageberak ( 2016-08-20 06:13:53 -0500 )edit

cool..thanx for feedback..i wont repeat it again

Venky009 gravatar imageVenky009 ( 2016-08-20 06:26:16 -0500 )edit
Login/Signup to Answer

Question Tools

1 follower

Stats

Asked: 2016-08-20 04:08:08 -0500

Seen: 3,660 times

Last updated: Aug 22 '16