I'm trying to build a new SimpleCV FeatureExtractor for openCV's Hough Circle Transform but I'm running into an error during my machine learning script's training phase.
I've provided the error below. It is raised by the Orange machine learning library when creating the self.mDataSetOrange variable within SimpleCV's TreeClassifier.py. The size of the dataset does not match Orange's expectation for some reason. I looked into Orange's source code and the found that error is thrown here:
orange/source/orange/cls_example.cpp
int const nvars = dom->variables->size() + dom->classVars->size();
if (Py_ssize_t(nvars) != PyList_Size(lst)) {
PyErr_Format(PyExc_IndexError, "invalid list size (got %i, expected %i items)",
PyList_Size(lst), nvars);
return false;
}
Obviously, my feature extractor is not extracting the things as required by Orange but I can't pinpoint what the problem could be. I'm pretty new to SimpleCV and Orange so I'd be grateful if someone could point out any mistakes I'm making.
The error:
Traceback (most recent call last):
File "MyClassifier.py", line 113, in <module>
MyClassifier.run(MyClassifier.TRAIN_RUN_TYPE, trainingPaths)
File "MyClassifier.py", line 39, in run
self.decisionTree.train(imgPaths, MyClassifier.CLASSES, verbose=True)
File "/usr/local/lib/python2.7/dist-packages/SimpleCV-1.3-py2.7.egg/SimpleCV/MachineLearning/TreeClassifier.py", line 282, in train
self.mDataSetOrange = orange.ExampleTable(self.mOrangeDomain,self.mDataSetRaw)
IndexError: invalid list size (got 266, expected 263 items) (at example 2)
HoughTransformFeatureExtractor.py
class HoughTransformFeatureExtractor(FeatureExtractorBase):
def extract(self, img):
bitmap = img.getBitmap()
cvMat = cv.GetMat(bitmap)
cvImage = numpy.asarray(cvMat)
height, width = cvImage.shape[:2]
gray = cv2.cvtColor(cvImage, cv2.COLOR_BGR2GRAY)
circles = cv2.HoughCircles(gray, cv2.cv.CV_HOUGH_GRADIENT, 2.0, width / 2)
self.featuresLen = 0
if circles is not None:
circleFeatures = circles.ravel().tolist()
self.featuresLen = len(circleFeatures)
return circleFeatures
else:
return None
def getFieldNames(self):
retVal = []
for i in range(self.featuresLen):
name = "Hough"+str(i)
retVal.append(name)
return retVal
def getNumFields(self):
return self.featuresLen
So, I figured out my issue. Basically, the problem was with the size of list returned by the extract method. The size of the list varied for each processed image, which is what led to this error. So, here are some examples of the type of lists returned by the extract method:
3 -> [74.0, 46.0, 14.866068840026855]
3 -> [118.0, 20.0, 7.071067810058594]
6 -> [68.0, 8.0, 8.5440034866333, 116.0, 76.0, 13.03840446472168]
3 -> [72.0, 44.0, 8.602325439453125]
9 -> [106.0, 48.0, 15.81138801574707, 20.0, 52.0, 23.409399032592773, 90.0, 122.0, 18.0]
Once I made sure that the size of the list was consistent, no matter the image, the error went away. Hopefully, this will help anyone having similar issues in the future.
Related
I am ready to pull my hair out, I have no idea what is going on.
I am performing watershed on an image I have. I have created markers for the watershed. I can apply the watershed on my original, 3 channel color image. HOWEVER, I need to do some image analysis prior to the watershed (noise reduction, etc., etc.).
Thus, the watershed applied to my original image does not turn out properly. Instead, I want to apply the watershed to an image with a distanceTransform applied, with my markers.
The relevant code:
# Need to watershed this
filled_img = filled_img.astype(np.uint8)
dist = cv2.distanceTransform(filled_img, cv2.DIST_L2, 0)
dist *= (1/dist.max())
dist3d = cv2.cvtColor(dist, cv2.COLOR_GRAY2BGR)
watershed_markers = cv2.watershed(dist3d, markers)
#watershed_markers = watershed(-dist, markers, mask=filled_img)
fig = plt.figure(figsize = (15,15))
plt.imshow(watershed_markers)
watershed_img = crop_img
watershed_img[watershed_markers==-1] == [255,0,0]
plt.figure(figsize=(20,20))
plt.imshow(watershed_img, 'jet')
However, no matter what I try, I get this error:
error Traceback (most recent call last)
new_BSA.ipynb Cell 12 in <cell line: 10>()
5 dist *= (1/dist.max())
7 dist3d = cv2.cvtColor(dist, cv2.COLOR_GRAY2BGR)
---> 10 watershed_markers = cv2.watershed(dist3d, markers)
11 #watershed_markers = watershed(-dist, markers, mask=filled_img)
13 fig = plt.figure(figsize = (15,15))
error: OpenCV(4.5.5) D:\a\opencv-python\opencv-python\opencv\modules\imgproc\src\segmentation.cpp:161: error: (-215:Assertion failed) src.type() == CV_8UC3 && dst.type() == CV_32SC1 in function 'cv::watershed'
Does anyone have any idea how to resolve this?
It is frustrating because my original image and the 3d distance image are both 3 channel images, I don't know why this error is showing up.
Any help is greatly appreciated
EDIT:
For a minimum reproducible example, I will start with my processed binary image, as I can't perform the watershed on my original image, which is shown here:
Original image
After processing, I get two binary images:
closing, on the left, which I use to obtain my markers, and filled_img on the right, which I want to apply the watershed to.
Processed image
From here, I extract the markers:
# Get difference between the two images, closing and filled_img
closing = closing.astype(np.uint8)
filled_img = filled_img.astype(np.uint8)
markers = cv2.subtract(filled_img, closing)
Then, I create a sure background from the image (areas close to the objects I know are background) by using dilation. Then, I extract the unknown regions, by using the difference between the sure foreground and my markers:
# sure background area
kernal = np.ones((3,3), np.uint8)
sure_bg = cv2.dilate(filled_img, kernal, iterations=3)
# sure fg area
sure_fg = markers
# unknown region
unknown = cv2.subtract(sure_bg, markers)
Then, following this example: https://docs.opencv.org/4.x/d3/db4/tutorial_py_watershed.html
I label my regions, ensuring that the unknown region is = 0, where the watershed will be flooded:
ret, markers = cv2.connectedComponents(sure_fg)
markers = markers+1
markers[unknown==True]=0
Here is an image of what the markers now looks like:
markers
Finally, from my initial post, I apply the watershed, where the error is appearing:
# Need to watershed this
filled_img = filled_img.astype(np.uint8)
dist = cv2.distanceTransform(filled_img, cv2.DIST_L2, 0)
dist *= (1/dist.max())
dist3d = cv2.cvtColor(dist, cv2.COLOR_GRAY2BGR)
watershed_markers = cv2.watershed(dist3d, markers)
#watershed_markers = watershed(-dist, markers, mask=filled_img)
fig = plt.figure(figsize = (15,15))
plt.imshow(watershed_markers)
watershed_img = crop_img
watershed_img[watershed_markers==-1] == [255,0,0]
I want to build an autoencoder with LSTM layers. But, at the first step of the encoder, I got an error. Could you please help me with that?
Here is the model which I tried to build:
import numpy
import torch.nn as nn
r_input = torch.nn.LSTM(1, 1, 28)
activation = nn.functional.relu
mu_r = nn.Linear(22, 6)
log_var_r = nn.Linear(22, 6)
y = np.random.rand(1, 1, 28)
def encode_r(y):
y = torch.reshape(y, (-1, 1, 28)) # torch.Size([batch_size, 1, 28])
hidden = torch.flatten(activation(r_input(y)), start_dim = 1)
z_mu = mu_r(hidden)
z_log_var = log_var_r(hidden)
return z_mu, z_log_var
But I got this error in my code:
RuntimeError: input.size(-1) must be equal to input_size. Expected 1, got 28.
You're not creating the layer in the correct way.
torch.nn.LSTM requires input_size as the first argument, but your tensor has a dimension of 28. It seems that you want the encoder to output a tensor with a dimension of 22. You're also passing the batch as the first dimension, so you need to include batch_first=True as an argument.
r_input = torch.nn.LSTM(28, 22, batch_first=True)
This should work for your specific setup. You should also note that LSTM returns 2 items, the first one is the one you want to use.
hidden = torch.flatten(activation(r_input(y)[0]), start_dim=1)
Please read the declaration on the official wiki for more information.
I am using Swift 3 and developing an application where the user takes a photo and uses Tesseract OCR to recognize the text in it.
The following code block works.
func processPhoto() {
if let tesseract = G8Tesseract(language: "eng") {
tesseract.delegate = self
// this is the resulting picture gotten after running the capture delegate
tesseract.image = stillPicture.image!
tesseract.recognize()
}
}
However, if I try to manipulate the picture at all (stillPicture.image!), I get the following error:
Error in pixCreateHeader: depth must be {1, 2, 4, 8, 16, 24, 32}
Error in pixCreateNoInit: pixd not made
Error in pixCreate: pixd not made
Error in pixGetData: pix not defined
Error in pixGetWpl: pix not defined
2017-03-13 11:13:05.336796 ProjectName[35238:9127211] Cannot convert image to Pix with bpp = 64
Error in pixSetYRes: pix not defined
Error in pixGetDimensions: pix not defined
Error in pixGetColormap: pix not defined
Error in pixClone: pixs not defined
Error in pixGetDepth: pix not defined
Error in pixGetWpl: pix not defined
Error in pixGetYRes: pix not defined
Please call SetImage before attempting recognition.Please call SetImage before attempting recognition.2017-03-13 11:13:05.343568 EOB-Reader[35238:9127211] No recognized text. Check that -[Tesseract setImage:] is passed an image bigger than 0x0.
Some things that I do to manipulate the picture is to rotate it:
// Rotate taken picture
let orig_image = stillPicture.image!
let new_image_canvas = UIGraphicsImageRenderer(size: CGSize(width: stillPicture.image!.size.height,
height: stillPicture.image!.size.width))
let new_image = new_image_canvas.image { _ in
let curr_context = UIGraphicsGetCurrentContext()!
curr_context.translateBy(x: 0, y: stillPicture.image!.size.width)
curr_context.rotate(by: -.pi/2)
stillPicture.image!.draw(at: .zero)
}
tesseract.image = new_image
If I do that, BOOM! The error above occurs.
Another manipulation I do is to crop portion of the image.
let finalImage : UIImage
let crop_section = CGRect(x: 590.0, y: 280.0, width: 950.0, height: 550.0)
let cg_image = stillPicture.image!.cgImage?.cropping(to: crop_section)
finalImage = UIImage(cgImage: cg_image!)
tesseract.image = final_image
Again, BOOM! Error appears. Any idea why this is happening and why my image manipulations are causing problems? Thanks for your help!
Whatever transformations you make to the image leave it in a format which Tesseract cannot understand. Tesseract uses the Leptonica library to handle image formats, and Leptonica can understand only images in a certain format.
The first line:
Error in pixCreateHeader: depth must be {1, 2, 4, 8, 16, 24, 32}
already is a big hint on what the error is. Bit depth means how many bits per pixel you have. For example a 24-bit image is usually RGB - you have 8-bits (or one byte) for red, green and blue each - total of 24-bits. 32-bits is for ARGB (RGB+alpha channel). 1 bit is monochrome.
See http://search.cpan.org/dist/Image-Leptonica/lib/Image/Leptonica/Func/pix1.pm#pixCreateHeader - pixCreateHeader is a leptopnica function.
So try the following - save the image to a file, and open it in some image editor and check what type of image it is, esp. the bit depth.
Apparently your image is using some weird bit depth. Also look at Node.js 20x slower than browser (Safari) with Tesseract.Js, because this is the only question that I could find where Error in pixCreateHeader: depth must be {1, 2, 4, 8, 16, 24, 32} is also mentioned.
I'm trying to automate the task of drawing lines with Gimp.
So I tried the scripting feature with no luck so far.
>>>from pprint import pprint
>>>img = gimp.Image(200, 200, RGB)
>>>pprint (pdb.gimp_pencil.params)
((16, 'drawable', 'The affected drawable'),
(0,
'num-strokes',
'Number of stroke control points (count each coordinate as 2 points) (num-strokes >= 2)'),
(8,
'strokes',
'Array of stroke coordinates: { s1.x, s1.y, s2.x, s2.y, ..., sn.x, sn.y }'))
>>>pdb.gimp_pencil(img, 4, [0,0,200,200] )
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: wrong parameter type
I couldn't find any example of passing a vector (Array of stroke coordinates) in Python for Gimp
What's wrong here?
Ok my mistake, I assumed the TypeError was on the last array argument. As it happens img is not the drawable, hence the TypeError.
You have to:
create an image
create a layer
add the layer to the image
set the layer active
obtain the active drawable of the image
Then only you can use this drawable in the gimp_pencil() method.
img = gimp.Image(200, 200, RGB)
layer = gimp.Layer(img, "Test", 200, 200, RGBA_IMAGE, 100, NORMAL_MODE)
img.add_layer(layer, -1)
pdb.gimp_image_set_active_layer(img, layer)
draw = pdb.gimp_image_get_active_drawable(img)
pdb.gimp_pencil(draw, 4, [0,0,100,100])
disp1 = gimp.Display(img)
I'm trying to get information from an image using the function cvGet2D in OpenCV.
I created an array of 10 IplImage pointers:
IplImage *imageArray[10];
and I'm saving 10 images from my webcam:
imageArray[numPicture] = cvQueryFrame(capture);
when I call the function:
info = cvGet2D(imageArray[0], 250, 100);
where info:
CvScalar info;
I got the error:
OpenCV Error: Bad argument (unrecognized or unsupported array type) in cvPtr2D, file /build/buildd/opencv-2.1.0/src/cxcore/cxarray.cpp, line 1824
terminate called after throwing an instance of 'cv::Exception'
what(): /build/buildd/opencv-2.1.0/src/cxcore/cxarray.cpp:1824: error: (-5) unrecognized or unsupported array type in function cvPtr2D
If I use the function cvLoadImage to initialize an IplImage pointer and then I pass it to the cvGet2D function, the code works properly:
IplImage* imagen = cvLoadImage("test0.jpg");
info = cvGet2D(imagen, 250, 100);
however, I want to use the information already stored in my array.
Do you know how can I solve it?
Even though its a very late response, but I guess someone might be still searching for the solution with CvGet2D. Here it is.
For CvGet2D, we need to pass the arguments in the order of Y first and then X.
Example:
CvScalar s = cvGet2D(img, Y, X);
Its not mentioned anywhere in the documentation, but you find it only inside core.h/ core_c.h. Try to go to the declaration of CvGet2D(), and above the function prototypes, there are few comments that explain this.
Yeah the message is correct.
If you want to store a pixel value you need to do something like this.
int value = 0;
value = ((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels +0];
cout << "pixel value for Blue Channel and (i,j) coordinates: " << value << endl;
Summarizing, to plot or store data you must create an integer value (pixel value varies between 0 and 255). But if you only want to test pixel value (like in an if closure or something similar) you can access directly to pixel value without using an integer value.
I think thats a little bit weird when you start but when you work with it 2 o 3 times you will work without difficulties.
Sorry, cvGet2D is not the best way to obtain pixel value. I know its the shortest and clear way because you in only one line of code and knowing coordinates obtain the pixel value.
I suggest you this option. When you see this code you you wiil think that is so complicated but is more effecient.
int main()
{
// Acquire the image (I'm reading it from a file);
IplImage* img = cvLoadImage("image.bmp",1);
int i,j,k;
// Variables to store image properties
int height,width,step,channels;
uchar *data;
// Variables to store the number of white pixels and a flag
int WhiteCount,bWhite;
// Acquire image unfo
height = img->height;
width = img->width;
step = img->widthStep;
channels = img->nChannels;
data = (uchar *)img->imageData;
// Begin
WhiteCount = 0;
for(i=0;i<height;i++)
{
for(j=0;j<width;j++)
{ // Go through each channel of the image (R,G, and B) to see if it's equal to 255
bWhite = 0;
for(k=0;k<channels;k++)
{ // This checks if the pixel's kth channel is 255 - it can be faster.
if (data[i*step+j*channels+k]==255) bWhite = 1;
else
{
bWhite = 0;
break;
}
}
if(bWhite == 1) WhiteCount++;
}
}
printf("Percentage: %f%%",100.0*WhiteCount/(height*width));
return 0;
This code count white pixels and gives you a percetage of white pixels in the image.