8

Here is what I have

im = cv2.imread('luffy.jpg')
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,127,255,0)

contours,h = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

for cnt in contours:

    // return color inside of the contour here
    mask = np.zeros(cnt.shape[:2],np.uint8)
    mean = cv2.mean(cant,mask)   // I think this is promising but so far it returns arrays with just zeros. I think its because I used np.zeros above to find the mask....
    moment = cv2.moments(cnt)   //maybe this will help?

I can find no such openCV function built in. I assume perhaps you can do it with the moments? How can I achieve this??

EDIT: with the proposed solution given by Zaw Lin I have this input image:

enter image description here

and this output image:

enter image description here

BigBoy1337
  • 4,735
  • 16
  • 70
  • 138
  • one way is: you can get the image area within the contour and then use it for further processing. Crop the internal area see this: http://stackoverflow.com/questions/28759253/how-to-crop-the-internal-area-of-a-contour – Vipul Jan 24 '16 at 07:09
  • I think the best way is to process the histogram of the inside image. [this](http://www.pyimagesearch.com/2014/01/22/clever-girl-a-guide-to-utilizing-color-histograms-for-computer-vision-and-image-search-engines/) may help. – Mahm00d Jan 24 '16 at 08:14
  • the first link seems to give a blank white cropping so I couldn't use it to find the color. The histogram might work, but it seems suited to make an actual histogram. I can't find a way to average the values of each channel for instance. I have found that you can run cv2.mean(cnt, mask) on a contour to get the mean values of the BGR channels, which seems promising. So far, no success though – BigBoy1337 Jan 24 '16 at 23:37

2 Answers2

17

This gets the average color inside each contour and draws contours with that color to final image.

import cv2
import numpy as np
im = cv2.imread('/home/zawlin/test.png')

gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
contours,h = cv2.findContours(gray,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

final = np.zeros(im.shape,np.uint8)
mask = np.zeros(gray.shape,np.uint8)

for i in xrange(0,len(contours)):
    mask[...]=0
    cv2.drawContours(mask,contours,i,255,-1)
    cv2.drawContours(final,contours,i,cv2.mean(im,mask),-1)

cv2.imshow('im',im)
cv2.imshow('final',final)
cv2.waitKey(0)
Zaw Lin
  • 5,629
  • 1
  • 23
  • 41
  • Im thinking this works, because there aren't any errors, however it does a horrible job. Are you getting good results with it? - the same image basically output with averaged colors... – BigBoy1337 Jan 27 '16 at 00:28
  • I did not test if the result is good or not. I just used the image @sturkmen posted and I have the same result as his. Maybe you can post your image? – Zaw Lin Jan 27 '16 at 00:31
  • i have given a sample in the question. clearly its not working very well yet, though I'm not sure what the cause is – BigBoy1337 Jan 27 '16 at 00:51
  • 1
    ah i think i understand what you are trying to do. i think a large part of whether it's "working" depends on the contour detection step but you cannot do it in this way. You need to perform some kind of segmentation algorithm. A typical method is just use kmeans to do color quantization. take a look here(http://docs.opencv.org/3.0-beta/_images/oc_color_quantization.jpg) is this what you are expecting? i have some code in c++ which can do this. – Zaw Lin Jan 27 '16 at 05:52
  • That is the affect I am looking for, but I would like to also to map the colors to their respective areas that they are filling. Thus I know that mario's hat is RGB=(243,23,42) for instance. In other words, does color quantization record the shapes of the polygons that are being filled? – BigBoy1337 Jan 27 '16 at 19:21
4

i think function mean with a mask image is the only way to get color inside a contour but sorry i can't show it by Python code.

you can get bounding box of a contour by boundingRect and use it to get image ROI from source image and binarized image for masking ( be aware of cloning binarized image because findcontour destroys it)

maybe a sample c++ will be useful ( sorry for my poor english.)

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

using namespace cv;
using namespace std;

int main( int, char** argv )
{
  /// Load source image
  Mat src = imread(argv[1]);
  if (src.empty())
  {
    cerr << "No image supplied ..." << endl;
    return -1;
  }

  /// Convert image to gray
  Mat src_gray;
  cvtColor( src, src_gray, COLOR_BGR2GRAY );
  threshold( src_gray, src_gray, 50, 255, THRESH_BINARY );
  imshow( "src_gray", src_gray );
  /// Find contours
  vector<vector<Point> > contours;
  findContours( src_gray.clone(), contours, RETR_TREE, CHAIN_APPROX_SIMPLE );

  Mat resImage0 = src.clone();
  Mat resImage1 = src.clone();
  /// Draw contours
  for( size_t i = 0; i< contours.size(); i++ )
     {
       Scalar color = Scalar( 0, 0, 255 );
       Rect _boundingRect = boundingRect( contours[i] );
       Scalar mean_color0 = mean( src( _boundingRect ) );
       Scalar mean_color1 = mean( src( _boundingRect ), src_gray( _boundingRect ) );

       drawContours( resImage0, contours, (int)i, mean_color0, FILLED );
       drawContours( resImage1, contours, (int)i, mean_color1, FILLED );
     }

  /// Show in a window
  imshow( "src", src );
  imshow( "resImage0", resImage0 );
  imshow( "resImage1", resImage1 );
  waitKey(0);
  return(0);
}

input image:

enter image description here

output images:

enter image description here enter image description here

sturkmen
  • 3,495
  • 4
  • 27
  • 63