I can't get rid of this error in OpenCV:
OpenCV Error: Sizes of input arguments do not match (The operation is
neither 'array op array' (where arrays have the same size and type),
nor 'array op scalar', nor 'scalar op array')
I found out with Mat.type(); that all of my Mat(img) has type 16 but after function inRange my img3 changed type to 0. Then I can't use function bitwise_and because it has not the same type.
How can I convert it to same type?
Mat img1 = imread(argv[1], 1);
Mat img2, img3, img4;
cvtColor(img1, img2, CV_BGR2HSV);
GaussianBlur(img2, img2, Size(15,15), 0);
inRange(img2, Scalar(h_min_min,s_min_min,v_min_min), Scalar(h_max_min,s_max_min,v_max_min), img3); // now img3 changed type to 0
bitwise_and(img1, img3, img4); // img1.type()=16, img3.type()=0 ERROR
This is normal, as inRange returns a 1-channel mask (a value for each pixel), so to perform the bitwise operation simply transform the mask back to 3-channel image:
cvtColor(img3,img3,CV_GRAY2BGR);
bitwise_and(img1, img3, img4);// now both images are CV_8UC3 (=16)
EDIT: as Berak says, to change the number of channels you must use cvtColor, not Mat::convertTo. Sorry about that.
Related
Here's how I call my image and define my button :
img = imread("lena.jpg");
createButton("Show histogram", showHistCallback, NULL, QT_PUSH_BUTTON, 0);
createButton("Equalize histogram", equalizeCallback, NULL, QT_PUSH_BUTTON, 0);
createButton("Cartoonize", cartoonCallback, NULL, QT_PUSH_BUTTON, 0);
imshow("Input", img);
waitKey(0);
return 0;
I can call and show my image properly. Function Show histogram and equalize histogram also work properly. But when I tried to call Cartoonize, I got this error :
[ WARN:0] global /home/hiro/Documents/OpenCV/opencv-4.3.0-source/modules/core/src/matrix_expressions.cpp (1334)
assign OpenCV/MatExpr: processing of multi-channel arrays might be changed in the future: https://github.com/opencv/opencv/issues/16739
terminate called after throwing an instance of 'cv::Exception'
what():OpenCV(4.3.0) /home/hiro/Documents/OpenCV/opencv-4.3.0-source/modules/core/src/arithm.cpp:669:
error: (-209:Sizes of input arguments do not match)
The operation is neither 'array op array' (where arrays have the same size and the same number of channels), nor 'array op scalar', nor 'scalar op array' in function 'arithm_op'
So I'm guessing my error comes from CartoonCallback function, channel error. I have made sure that my mutiplication is between image of same channels, I converted everything back to 3 channels, yet I can't seem to figure out where the error comes from. Here's the code :
void cartoonCallback(int state, void* userdata){
Mat imgMedian;
medianBlur(img, imgMedian, 7);
Mat imgCanny;
Canny(imgMedian, imgCanny, 50, 150); //Detect edges with canny
Mat kernel = getStructuringElement (MORPH_RECT, Size(2,2));
dilate(imgCanny, imgCanny, kernel); //Dilate image
imgCanny = imgCanny/255;
imgCanny = 1 - imgCanny;
Mat imgCannyf; //use float values to allow multiply between 0 and 1
imgCanny.convertTo(imgCannyf, CV_32FC3);
blur(imgCannyf, imgCannyf, Size(5,5));
Mat imgBF;
bilateralFilter(img, imgBF, 9, 150.0, 150.0); //apply bilateral filter
Mat result = imgBF/25; //truncate color
result = result*25;
Mat imgCanny3c; //Create 3 channels for edges
Mat cannyChannels[] = {imgCannyf, imgCannyf, imgCannyf};
merge(cannyChannels, 3, imgCanny3c);
Mat resultFloat;
result.convertTo(imgCanny3c, CV_32FC3); //convert result to float
multiply(resultFloat, imgCanny3c, resultFloat);
resultFloat.convertTo(result, CV_8UC3); //convert back to 8 bit
imshow("Cartoonize", result);
}
Any suggestion ?
The problem is within this snippet:
cv::Mat resultFloat; // You prepare an output mat... with no dimensions nor type
result.convertTo(imgCanny3c, CV_32FC3); //convert result to float..ok
cv::multiply(resultFloat, imgCanny3c, resultFloat); //resultFloat is empty and has no dimensions!
As you can see, you pass resultFloat to cv::multiply(operand1, operand2, output), but resultFloat is empty, without dimensions nor type and then attempt to multiply it with imgCanny3c. This seems the cause of the error.
I am creating a code for change detection in C++ using OpenCV but this code shows runtime error if I change the the image
void MainWindow::on_pushButton_2_clicked()
{
cv::Mat input1 = cv::imread("C:\\Users\\trainee2017233\\Desktop\\pre-post\\sulamani_ms1p1_pre_gref.tif");
cv::Mat input2 = cv::imread("C:\\Users\\trainee2017233\\Desktop\\post-post\\sulamani_ms1p1_pre_gref.tif");
cv::Mat diff;
cv::absdiff(input1, input2, diff);
cv::Mat diff1Channel;
// WARNING: this will weight channels differently! - instead you might want some different metric here. e.g. (R+B+G)/3 or MAX(R,G,B)
cv::cvtColor(diff, diff1Channel, CV_BGR2GRAY);
float threshold = 30; // pixel may differ only up to "threshold" to count as being "similar"
cv::Mat mask = diff1Channel < threshold;
cv::imshow("similar in both images" , mask);
// use similar regions in new image: Use black as background
cv::Mat similarRegions(input1.size(), input1.type(), cv::Scalar::all(0));
// copy masked area
input1.copyTo(similarRegions, mask);
cv::imshow("input1", input1);
cv::imshow("input2", input2);
cv::imshow("similar regions", similarRegions);
cv::imwrite("../outputData/Similar_result.png", similarRegions);
cv::waitKey(0);
}
when I am writing both images as the same image then no error is there but while changing them to different images it shows the error
OpenCV Error: Sizes of input arguments do not match (The operation is neither 'array op array' (where arrays have the same size and the same number of channels), nor 'array op scalar', nor 'scalar op array') in arithm_op, file D:\opencv\sources\modules\core\src\arithm.cpp, line 659
Here input1 and input2 should be of the same size for the function absdiff
...
cv::resize(input2, input2, input1.size());
cv::Mat diff;
...
I have a black/white image and a colour image of same size. I want to combine them to get one image which is black where black/white image was black and same colour as coloured image where black/white image was white.
This is the code in C++:
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(){
Mat img1 = imread("frame1.jpg"); //coloured image
Mat img2 = imread("framePr.jpg", 0); //grayscale image
imshow("Oreginal", img1);
//preform AND
Mat r;
bitwise_and(img1, img2, r);
imshow("Result", r);
waitKey(0);
return 0;
}
This is the error message:
OpenCV Error: Sizes of input arguments do not match (The operation is neither 'array op array' (where arrays have the same size and type), nor 'array op scalar', nor 'scalar op array') in binary_op, file /home/voja/src/opencv-2.4.10/modules/core/src/arithm.cpp, line 1021
terminate called after throwing an instance of 'cv::Exception'
what(): /home/voja/src/opencv-2.4.10/modules/core/src/arithm.cpp:1021: error: (-209) The operation is neither 'array op array' (where arrays have the same size and type), nor 'array op scalar', nor 'scalar op array' in function binary_op
Aborted (core dumped)
Firstly, a black/white(binary) image is different from a grayscale image. Both are Mat's of type CV_8U. But each pixel in grayscale image could take any value between 0 and 255. A binary image is expected to have only two values - a zero and a non zero number.
Secondly, bitwise_and cannot be applied to Mat's of different type. Grayscale image is a single channel image of type CV_8U( 8 bits per pixel ) and color image is a 3 channel image of type CV_BGRA ( 32 bits per pixel ).
It appears what you are trying to do could be done with a mask.
//threshold grayscale to binary image
cv::threshold(img2 , img2 , 100, 255, cv::THRESH_BINARY);
//copy the color image with binary image as mask
img1.copyTo(r, img2);
Actually, it is fairly simple using img1 as mask in a copyTo:
//Create a black colored image, with same size and type of the input color image
cv::Mat r = zeros(img2.size(),img2.type());
img1.copyTo(r, img2); //Only copies pixels which are !=0 in the mask
As said by Kiran, you get an error because bitwise_and cannot operate on image of different type.
As noted by Kiran, the initial allocation and zeroing is not mandatory (however doing things preliminarily has no impact on the performance). From the documentation:
When the operation mask is specified, if the Mat::create call shown
above reallocates the matrix, the newly allocated matrix is
initialized with all zeros before copying the data.
So the whole operation can be done with a simple:
img1.copyTo(r, img2); //Only copies pixels which are !=0 in the mask
Here is my code. It's pretty simple.
Mat image = imread("filename.png");
imshow("image", image);
waitKey();
//Image looks great.
Mat image_gray;
image.convertTo(image_gray, CV_RGB2GRAY);
imshow("image", image_gray);
waitKey();
But when I call the image.convertTo(image_gray, CV_RGB2GRAY); line, I get the following error message:
OpenCV Error: Assertion failed (func != 0) in unknown function, file ..\..\..\sr
c\opencv\modules\core\src\convert.cpp, line 1020
Using OpenCV 2.4.3
The method convertTo does not do color conversion.
If you want to convert from BGR to GRAY you can use the function cvtColor:
Mat image_gray;
cvtColor(image, image_gray, CV_BGR2GRAY);
The function cv::Mat::convertTo is not for color conversion. It is for type conversion. The destination image should have same size and number of channels as the source image.
To convert from RGB to Gray, use the function cv::cvtColor.
cv::cvtColor(image,image_gray,CV_RGB2GRAY);
If you need to acquire video (e.g. from a webcam) in Grayscale, you can also set the saturation of the video feed to zero. (Ex. in Python syntax)
capture = cv.CaptureFromCAM(camera_index)
...
cv.SetCaptureProperty(capture, cv.CV_CAP_PROP_SATURATION,0)
image.convertTo(image_gray, CV_RGB2GRAY);
This's wrong.Correct one is,
Mat gray_image;
cvtColor(image, gray_image, CV_BGR2GRAY);
Try this.
In OpenCV, if I have a Mat img that contains uchar data, how do I convert the data into float? Is there a function available? Thank you.
If you meant c++ then you have
#include<opencv2/opencv.hpp>
using namespace cv;
Mat img;
img.create(2,2,CV_8UC1);
Mat img2;
img.convertTo(img2, CV_32FC1); // or CV_32F works (too)
details in opencv2refman.pdf.
UPDATE:
CV_32FC1 is for 1-channel (C1, i.e. grey image) float valued (32F) pixels
CV_8UC1 is for 1-channel (C1, i.e. grey image) unsigned char (8UC) valued ones.
UPDATE 2:
According to Arthur Tacca, only CV_32F is correct (or presumably CV_8U), since convertTo should not change the number of channels. It sounds logical right? Nevertheless, when I have checked opencv reference manual, I could not find any info about this, but I agree with him.
Use cvConvert function. In Python:
import cv
m = cv.CreateMat(2, 2, cv.CV_8UC1)
m1 = cv.CreateMat(2, 2, cv.CV_32FC1)
cv.Convert(m, m1)