2

I want to detect how many number of cards are present in this image using python.I was trying with white pixel but not getting the correct result.enter image description here

My code is given below:

import cv2
import numpy as np

img = cv2.imread('imaagi.jpg', cv2.IMREAD_GRAYSCALE)
n_white_pix = np.sum(img == 255)
print('Number of white pixels:', n_white_pix)

I am a beginner. So unable to find out the way.

Shaon Paul
  • 153
  • 1
  • 2
  • 14
  • 1
    The general problem with summing over the "255" pixels is that it might not be necessarily true that all pixels of a card are exactly 255; in "real" images, a slight perturbance might lead to slightly differing values. Even so, summing over these will give you (potentially) *vastly more* results than intended. – dennlinger Jul 18 '18 at 11:18
  • Then How to determine the value???? – Shaon Paul Jul 18 '18 at 11:55
  • By working with a *processed* image. One of many approaches is described in my answer, and you can find many more by looking for terms like "image segmentation" or "object detection". – dennlinger Jul 18 '18 at 11:58

2 Answers2

3

This solution is with respect to the image you have provided and the implementation is in OpenCV.

Code:

im = cv2.imread('C:/Users/Jackson/Desktop/cards.jpg', 1)

#--- convert the image to HSV color space ---
hsv = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)
cv2.imshow('H', hsv[:,:,0])
cv2.imshow('S', hsv[:,:,1])

#--- find Otsu threshold on hue and saturation channel ---
ret, thresh_H = cv2.threshold(hsv[:,:,0], 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
ret, thresh_S = cv2.threshold(hsv[:,:,1], 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

#--- add the result of the above two ---
cv2.imshow('thresh', thresh_H + thresh_S)

#--- some morphology operation to clear unwanted spots ---
kernel = np.ones((5, 5), np.uint8)
dilation = cv2.dilate(thresh_H + thresh_S, kernel, iterations = 1)
cv2.imshow('dilation', dilation)

#--- find contours on the result above ---
(_, contours, hierarchy) = cv2.findContours(dilation, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

#--- since there were few small contours found, retain those above a certain area ---
im2 = im.copy()
count = 0
for c in contours:
    if cv2.contourArea(c) > 500:
        count+=1
        cv2.drawContours(im2, [c], -1, (0, 255, 0), 2)

cv2.imshow('cards_output', im2)
print('There are {} cards'.format(count))

Result:

On the terminal I got: There are 6 cards

enter image description here

Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
0

Depending on how exactly your "white pixel approach" was working (please share more details on that if possible), you could try a simple image binarization, which is a well-established way of separating different objects/entities in your image. Granted, it will work only on grayscale images, but that is something you can also easily fix with sklearn.

It might provide optimal results right away, especially if the lighting conditions vary across images, or you have (as seen above) cards that contain a wide variety of colors.

To circumvent this, you could also try to look into different color spaces, e..g HSV.

If that still does not work, I would recommend using image segmentation libraries from OpenCV or similra libraries. The problem is that they usually also bring some unwanted complexity to your project, which might not be necessary if it works with a simple approach such as the binarization.

dennlinger
  • 9,890
  • 1
  • 42
  • 63
  • I provided you with a link to a quite comprehensive code example, which you can easily apply to your image as well. You can try and see whether this approach will work for your specific case. – dennlinger Jul 18 '18 at 11:19
  • Stackoverflow is generally a place to look for *direction*, not for people to produce code for you that will solve your problem. You have to show that you at leats tried some of the proposed approaches, or clarify where exactly you are having a problem (i.e., "I am unable to convert my image to grayscale", or "the results of my image look very strange"). – dennlinger Jul 18 '18 at 11:21