3
cv2.error: OpenCV(4.2.0) c:\projects\opencv
python\opencv\modules\imgproc\src\color.simd_helpers.hpp:92: error:
(-2:Unspecified error) in function '__cdecl cv::impl::`anonymous- 

namespace'::CvtHelper<struct cv::impl::`anonymous
namespace'::Set<3,4,-1>,struct cv::impl::A0xe227985e::Set<1,-1,-1>,struct cv::impl::A0xe227985e::Set<0,2,5>,2>::CvtHelper(const class cv::_InputArray &,const class cv::_OutputArray &,int) > Invalid number of channels in input image: > 'VScn::contains(scn)' > where > 'scn' is 1

img = cv2.cvtColor(images, cv2.COLOR_BGR2GRAY) 

this line gives me error

hello everyone i am new to use opencv, now i am doing project on image classification

my complete code as follows

from flask import Flask, request
from flask_restful import Api, Resource
import sys, os
from myconstants1 import path_logs, path_resources
from logConfig1 import setup_logger
import pathlib, pycountry, cv2, pickle, random, PIL, sys
from pathlib import Path 
import pathlib as pl
import numpy as np
from sklearn.model_selection import train_test_split
import pandas as pd
import matplotlib.pyplot as plt
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import Adam
from keras.utils.np_utils import to_categorical
from keras.layers import Flatten, Dropout
from keras.layers.convolutional import Conv2D, MaxPooling2D
from keras.preprocessing.image import ImageDataGenerator
from PIL import Image, ImageOps
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

logger = setup_logger('/modelTrain', path_logs+'/modelTrain.log')

app = Flask(__name__)
api = Api(app)

path = sys.path
path = Path(__file__).parent

print("path2", path)

class HandleRequest5(Resource):
    y_validation = ""
    x_test = ""
    x_validation  = ""
    x_train = ""
         
    @classmethod
    def post(cls, json): 
               
        data = request.get_json()
        
        json = ({
            "Status": "failed",
            "message": "ALL fields are mandatory"
                })
                
        try:
            country_code = data["country_code"].upper()  
            batch_size = data["batch_size"]
            step_per_epoch_val = data["step_per_epoch_val"]
            epoch = data["epoch"]
        except KeyError:
            print(json)
            logger.debug(json)
            return(json)

        
        try:
            country = pycountry.countries.get(alpha_3 = data["country_code"].upper()).name.lower()
            print("country1", country)
            logger.debug(f'country1 : {country}')
            country = country.split()
            country =("_".join(country))
            print("country : ", country)
            logger.debug(f"country : {country}")
            alpha_2 = pycountry.countries.get(alpha_3 = data["country_code"].upper()).alpha_2
            print("alpha_2 : ", alpha_2)
            logger.debug(f"alpha_2 : {alpha_2}")
        except AttributeError:                
            jsonify1 = {
                        "status": "invalid",
                        "message" : "Invalid country_code"
                        }
            print("invalid country_code")
            
            logger.debug({
                        "status": "invalid",
                        "message" : "Invalid country_code"
                        })
            return jsonify1
    
    #   path = rf'{path}/{country}'  # folder with all class folders
        
        labelFile = rf'{path_resources}/{country}/labels.csv'         
        imageDimensions = (99, 200, 3)
        print("imageDimensions:", imageDimensions)
        testRatio = 0.2               # if 1000 images split will 200 for testing
        validationRatio = 0.2  
        print("line 91 is going to execute")
        cls.importImages( cls,testRatio , validationRatio , imageDimensions  ,country , labelFile)   
        
    def importImages(cls, testRatio, validationRatio, imageDimensions, country, labelFile):
        count = 0
        images = []
        classNo = []
        

        p = pl.Path(f'{path_resources}/{country}')                    
        mylist = [x for x in p.iterdir() if x.is_dir()]
        print("mylist1", mylist)
        print("total classs detected :", len(mylist))
        noofClasses = len(mylist)
        print("noofClasses:", noofClasses)
        print("importing classes...")
        
        for x in range(0, len(mylist)):

            myPicList = os.listdir(os.path.join(str(path_resources), str(country)+'//'+str(count))) 
            print("myPicList1:", myPicList)

            #for y in myPicList:
                #print(os.path.join(path, str(count), y))
                #curImg = cv2.imread((str(path_resources)+"/"+str(count)+"//"+y))
                
            for y in myPicList:
                print(os.path.join(path_resources, country, str(count)+y))

                curImg = cv2.imread(f"{path_resources}{country}/{str(count)}//{y}")                                                      
                images.append(curImg)
                classNo.append(count)
            print(count, end = " ")
            count+=1
        print(" ")
        images = np.array(images, dtype=np.uint8) 
        images = np.array(images)
        print("line 128")
        print(images.shape)
        #images = np.append(images,4)
        #images = images.append((Image.fromarray(images, dtype=np.float32).convert('RGB') / 255.))
#        image = Image.fromarray(images)
        #images = images.convert("RGB")
        classNo = np.array(classNo)        
        
        cls.splitData(cls,images, classNo, testRatio, validationRatio , imageDimensions, labelFile, noofClasses)
        return images, classNo, noofClasses
        
        # split data #
    def splitData(cls, images, classNo, testRatio, validationRatio , imageDimensions, labelFile, noofClasses):

        x_train, x_test, y_train, y_test = train_test_split(images, classNo, test_size = testRatio)
        x_train, x_validation, y_train, y_validation = train_test_split(x_train, y_train , test_size = validationRatio)
        
        # to check if no of images matches to number of labels for each data set
        print("data shapes...")
        print("train : ", end = "");print(x_train.shape, y_train.shape)
        print("validation :", end = ""); print(x_validation.shape, y_validation.shape) 
        print("test :", end = ""); print(x_test.shape, y_test.shape)        
        
        assert (x_train.shape[0] == y_train.shape[0]),  "the no of images is not equal to the no of labels in training set"
        assert (x_validation.shape[0] == y_validation.shape[0]), "the no of images is not equal to the no of labels in validation set"
        assert (x_test.shape[0] == y_test.shape[0]), "the no of images is not equal to the no of labels in test set"
        #print(x_train.shape)
        assert (x_train.shape[1:]  == (imageDimensions)),  "the dimension of training images are wrong"
        assert (x_validation.shape[1:] == (imageDimensions)), "the dimension of validation images are wrong"
        assert (x_test.shape[1:] == (imageDimensions)), "the dimension of test images are wrong"        
        
        data = pd.read_csv(labelFile) 
        
        cls.grayscale(cls, images, x_train, x_validation, x_test, y_train, y_validation, y_test )
        
        return images, x_train, x_validation, x_test, y_train, y_validation, y_test
        # preprocessing the image #

    def grayscale(cls,images, x_train, x_validation, x_test, y_train, y_validation, y_test):
        #images = ImageOps.grayscale(images)
        images = cv2.cvtColor(images, cv2.COLOR_BGR2GRAY)
        cls.equalize(images)
        return images
        
    def equalize(images):
        img = cv2.equalizeHist(images)       
        cls.preprocessing(img, grayscale, equalize)
        return img
        
    def preprocessing(cls, img, grayscale, equalize, x_train, x_validation, x_test, y_train, y_test, y_validation):
        img = grayscale(img)  #convert to grayscale
        img = equalize(img)   #standardize the lightining of an image
        img = img/255         # to normaize value between 0 and 1 instead of 0 to 255
        return img , x_train, x_validation, x_test, y_train, y_test, y_validation

        x_train = np.array(list(map(preprocessing, x_train)))  # to iterate and preprocess all images
        x_validation = np.array(list(map(preprocessing, x_validation)))
        x_test = np.array(list(map(preprocessing, x_test)))

        #cv2.imshow("grayscale images", x_train[random.randint(0, len(x_train)-1)]) #to check if training is done properly
               
        # add a depth of 1 #

        x_train = x_train.reshape(x_train.shape[0], x_train.shape[1], x_train.shape[2], 1)
        x_validation = x_validation.reshape(x_validation .shape[0], x_validation .shape[1], x_validation .shape[2], 1)
        x_test = x_test.reshape(x_test.shape[0], x_test.shape[1], x_test.shape[2], 1)


    def dataAugmentation(cls, x_train, y_train, noofClasses):
    # augmentation of images to make it more generic #

        dataGen = ImageDataGenerator(width_shift_range = 0.1, 
                             height_shift_range  = 0.1,
                             zoom_range = 0.2,
                             shear_range = 0.1,
                             rotation_range = 10)

        dataGen.fit(x_train)
        batches = dataGen.flow(x_train, y_train, batch_size = 20)
        x_batch, y_batch = next(batches)


# to show augmentated image sample 
#fig, axs = plt.subplots(24, 2, figsize = (20, 5))
#fig.tight_layout()
#print(axs)
#print("axs0:",axs[0])
#print("axs1:",axs[1])
#for i in range(10):
    #axs[i].imshow(x_batch[i].reshape(imageDimensions[0], imageDimensions[1]))
    #axs[0][1].imshow(x_batch[i].reshape(imageDimensions[0], imageDimensions[1]))
    #axs[i].axis("off")
    #axs[0][1].axis('off')
#plt.show()

        y_train = to_categorical(y_train, noofClasses) 
        y_validation = to_categorical(y_validation, noofClasses) 
        y_test = to_categorical(y_test, noofClasses) 
        cls.splitData(y_validations)        
        cls.myModel(noofClasses)
# convolution neural network #

    def myModel(cls, noofClasses, country):
        no_of_filters = 60 
        size_of_filter = (5,5)  #this is kernal that move around the image to get the features 
    
        size_of_filter2 = (3,3) 
        size_of_pool = (2,2)
        no_of_nodes = 200
    
        model = Sequential()
        model.add(Conv2D(no_of_filters, size_of_filter, input_shape = (imageDimensions[0], imageDimensions[1], 1), activation = "relu"))
        model.add(Conv2D(no_of_filters, size_of_filter, activation = "relu"))
        model.add(MaxPooling2D(pool_size = size_of_pool))
    
        model.add(Conv2D(no_of_filters//2, size_of_filter2, activation = "relu"))
        model.add(Conv2D(no_of_filters//2, size_of_filter2, activation = "relu"))
        model.add(Dropout(0.5))
    
        model.add(Flatten())
        model.add(Dense(no_of_nodes, activation = "relu"))
        model.add(Dropout(0.5))
    
    
  #  model.add(Flatten())
        model.add(Dense(noofClasses, activation = "softmax"))
    
    # compile model #
        model.compile(Adam(lr = 0.001), loss = "categorical_crossentropy",  metrics = ["accuracy"])
        return model    
    
    # train #
        model = myModel()

        print(model.summary())
        history = model.fit_generator  (dataGen.flow(x_train, y_train, batch_size = batch_size_val), steps_per_epoch = steps_per_epoch_val, epochs = epoch_val, validation_data = (x_train, y_train))  
        
# plot #

        plt.figure(1)
        plt.plot(history.history["loss"])
        plt.plot(history.history["val_loss"])
        plt.legend(["training", "validation"])

        plt.title("loss")
        plt.xlabel("epoch")
        plt.figure(2)
        plt.plot(history.history["accuracy"])
        plt.plot(history.history["val_accuracy"])

        plt.legend(["training", "accuracy"])
        plt.title("accuracy")
        plt.xlabel("epoch")
        #plt.show()


        score = model.evaluate(x_test, y_test, verbose = 0)
        print("test score: ", score[0])
        print("test accuracy: ", score[1])

    ###############################################################
    #store the model as pickle object #
    #save_path = rf'{path}/{country}'
        pickle_out = open(rf"{path_resources}/{country}.p", "wb")
    #model = model.save(rf'{country}_{epoch_val}.h5')

        pickle.dump(model, pickle_out)
        pickle_out.close()
        print(rf"{country}_model saved...")
        cv2.waitKey(0)        

        
api.add_resource(HandleRequest5, '/modelTrain')
if __name__ == ' __main__ ':
    app.run(debug = False)
shubhamb
  • 41
  • 1
  • 1
  • 5
  • 1
    This error is common when the input shape is not correct. Can you verify the input shape of the image? In any case `print(img.shape)`, it should be something like `(int, int, 3)`. Also if you would our help we need to at least be able to reproduce the problem. Provide some [minimal working example](https://stackoverflow.com/help/minimal-reproducible-example) for us to work with. – Thymen Dec 21 '20 at 07:22
  • hello thymen, thanks for your advice. plz see imageDimensions = (99, 200, 3) @Thymen – shubhamb Dec 21 '20 at 07:44
  • when i did `print(images.shape)` i get `(336, 99, 200, 3)` @Thymen – shubhamb Dec 21 '20 at 07:52
  • Most probably you have 336 images which dimension is `99, 200, 3`. If I'm correct, then you need to read it, one by one, i.e. `cv2.imread`, then convert it to the grey-scale. – Ahmet Dec 21 '20 at 07:57
  • hello @Ahx , thanks for your response. I have 336 mages in total which dimensions `(99, 200, 3)` . in my project i am doing image classificaton – shubhamb Dec 21 '20 at 08:03
  • `File "E:\demo3\modules\modelTrain.py", line 177, in grayscale gry = cv2.cvtColor(images, cv2.COLOR_BGR2GRAY) cv2.error: OpenCV(4.2.0) c:\projects\opencv-python\opencv\modules\imgproc\src\color.simd_helpers.hpp:92: error: (-2:Unspecified error) in function '__cdecl cv::impl::`anonymous-namespace'::CvtHelper – shubhamb Dec 21 '20 at 10:44
  • i am again started getting the above error `cv2.error: OpenCV(4.2.0) c:\projects\opencv` – shubhamb Dec 21 '20 at 10:45

1 Answers1

2

As suggested in the comments, you have two ways to do this. You can either iterate through each image and run the cv2.cvtColor method or you can use the formula to convert from RGB to grayscale directly. OpenCV uses the SMPTE Rec. 601 conversion formula, which is:

Y = 0.299*R + 0.587*G + 0.114*B

Let's cover both methods.

Method #1

Create a new 3D array that is 336 x 99 x 200 then iterate through each image in your 4D array, convert then set it to the corresponding location in the output.

images_gray = np.zeros(images.shape[:-1], dtype=images.dtype)
for i, img in enumerate(images):
    images_gray[i] = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

Method #2 - Use the conversion formula directly

I would argue that this method is the most efficient, mainly because what I will suggest that you do is compute this vectorized:

coeffs = np.array([0.114, 0.587, 0.229])
images_gray = (images.astype(np.float) * coeffs).sum(axis=-1)
images_gray = images_gray.astype(images.dtype)

Two things to note: The first is that the weights for each of the RGB values are reversed due to OpenCV reading images in BGR format. The second is that I have temporarily cast the images to floating-point precision so that you maintain the most accuracy possible due to the floating-point coefficients. We then convert the resulting output back to the same precision as your input images. Finally, what the above code will do is for every pixel for every image, we will multiply each colour pixel by the weights seen in the conversion formula, then sum over the values. The above code will do it in a vectorized way with no loops.

Minor note regarding image classification

I noticed in the comments thread above that you are using this to perform image classification. If you plan on using a deep learning framework, you usually need to maintain a singleton dimension to reflect the channel dimension so that you can properly do broadcasting in the forward pass of the network. In other words, you must have a 336 x 99 x 200 x 1 array. For method #1, simply declare your output array to have the four dimensions, but in the loop you will need to add a singleton dimension to the end of your array by using np.newaxis.

images_gray = np.zeros(images.shape, dtype=images.dtype)
for i, img in enumerate(images):
    images_gray[i] = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)[..., np.newaxis]

For method #2, you can add keepdims=True in the sum call:

coeffs = np.array([0.114, 0.587, 0.229])
images_gray = (images.astype(np.float) * coeffs).sum(axis=-1, keepdims=True)
images_gray = images_gray.astype(images.dtype)
rayryeng
  • 102,964
  • 22
  • 184
  • 193
  • thanks for your response, can u plz check my above code ? – shubhamb Dec 21 '20 at 10:01
  • 1
    Your code is too long to go through. Please provide a [mcve] – rayryeng Dec 21 '20 at 11:00
  • hello rayryeng, i am new to stack overtflow. i try to give u required part of code which u are interested. ``` def grayscale(cls,images, x_train, x_validation, x_test, y_train, y_validation, y_test):``` ```ret_lst = []``` for img in images: ```gry = cv2.cvtColor(images, cv2.COLOR_BGR2GRAY)``` ```ret_lst.append(gry)``` ```cls.equalize( images, ret_lst)``` ```return images, ret_lst ``` – shubhamb Dec 21 '20 at 11:06
  • hello rayryeng, i try to give u the part of my code but it is not in the correct format. can u plz check the `grayscale method` in above code. – shubhamb Dec 21 '20 at 11:39