In Matlab, I can use logical(img) to convert all non-zero element to one.
Is there a simple way(i.e. without loop) to convert all non-zero stored in cv::Mat to one in OpenCV?
Thanks!
There number of functions that may help you but that depends on what you have and what you are trying to get.
1) OpenCV has function compare and operator '!=' (as well as any other operator you may need). You can write:
img = (img != 0);
This will convert any non-zero value of matrix to 255. I know that you wanted to convert it to 1, but if 255 is good enough for you than this is the best method. In any task I encountered in the past conversion to 255 was always better than conversion to 1, because you can use resulting image for all kinds of bitwise operations like logic AND, OR, etc...
2) If you do want to make conversion to 1, and your matrix is positive integers (or chars, or shorts), you can use function min.
img = min(img,1);
3) Also you can use function threshold as #Roger Rowland suggested.
You could use the threshold() function in OpenCV for convenience.
You mention "non-zero" elements. If your matrix has negative numbers, and you still want those to be set to 1, use threshold( abs(my_mat), .. ).
In general, this can also be done through this:
Mat my_mat;
Mat reference = Mat::zeros( rows, cols, type );
Mat result = (abs(my_mat) > reference)/255;
This is longer, and probably looks messier, but it has the advantage that reference can be adjusted to something other than all zeros if required (it could be a gradient, for example). Also, < is not the only operator that can fit there- any logical operator can be used. The result of a logical operation is always either 0 or 255, hence the division.
Related
I have a tif image in which its pixel are integers. I want to import it to Julia and process it further.
I used in IJulia:
using FileIO
using Images
using ImageView
path_seed = joinpath(#__DIR__,"seed.tif")
seed = load(path_seed);
When I enter seed and enter I will get an image while I want the matrix of elements.
If I use:
mat = convert(Array{Float32}, seed)
I will get a matrix but there are two problems:
1- Its entries are all float but not an integer.
2- The value of the float does not correspond to the value of integers I expect. For example, in my images there are values 0,1,2,3,4 (the image is a mask and each connected component have values of 0,1,2,3,4) but I get floats 0.0, 0.011764707, 0.015686275, 0.007843138, 0.003921569.
How can I import the image as a matrix of integers? Here is the sample image:
http://s000.tinyupload.com/index.php?file_id=21432720633236092551
When you load that file, you're seeing the effects of two of the key abstractions of JuliaImages:
every pixel is a single entry in an array (not, e.g., 3 entries if it's an RGB image)
numbers mean what they say they are. In particular, 255 ≠ 1.0.
When you load your seed.tif image, you'll note that the returned values are of type Gray{N0f8}. The Gray part means it has been interpreted as a grayscale image---had it been a color image, they might have been elements like RGB{N0f8}(1.0, 0.8, 0.4). In either case, accessing img[i,j] returns all the information about that whole pixel.
The part you're probably most concerned about is the N0f8. In most image-processing frameworks, the meaning of a number depends on its representation (e.g., https://scikit-image.org/docs/stable/user_guide/data_types.html). "White" is 255 if your numbers are encoded as UInt8, but white is 1.0 if your numbers are encoded as Float32. When you want to change the representation, you have to remember to use special conversion functions that also change the values of the pixels. In no other field of mathematics am I aware of the equality 255 == 1.0.
To stop encouraging bad mathematics, JuliaImages has gone to the trouble to define new number types that harmonize these notions. In JuliaImages, white is always 1. But to support 8-bit images, we define a new number type, N0f8, with 8 bits whose maximum value is 1. These are internally represented just like UInt8, they are just interpreted as if they have been divided by 255. Similarly, there are N0f16 for 16-bit images, and even special types like N4f12 that are useful, e.g., if you're collecting images with a 12-bit camera. This means it's possible to detect image saturation simply by looking for pixels with value 1.
Of course, sometimes you might want to look at things differently. JuliaImages supports several "views" that provide an alternative interpretation of the same bitwise data. In your case,
rawview(channelview(seed))
would return an array of UInt8 values which might be what you're expecting.
Note, however, that if you want to save an array of integers that shouldn't really be interpreted as an image, there are possibly better formats such as HDF5. Image formats are sometimes subject to compression that can corrupt the values you save. TIFF is often called lossless, but in fact it's possible to use lossy compression (https://en.wikipedia.org/wiki/TIFF).
I frequently encounter that issue but I don't really know a proper way to fix it.
I just would like some advise to do it the regarding to the processing time.
I am using opencv and I want to realize that operation:
map |= mask & mu(0);
map is a matrix of single precision float.
mask is a matrix of unsigned char that only contain 0 for the statement false ot 255 (0xFF) for the statement true
mu is a double precision float scalar value.
Usually I do realize that operation that way :
cv::multiply(mask,mu(0),mask, 1./255., CV_32F);
map |= mask
Regarding also to the transparent vectorize classes (header openc2/core/hal/intrinsics.hpp) is there a more efficient way to do such operation ?
Thank you in advance for any help.
As highlighted by api55 could be fix by using directly the bitwise function rather than using the operator overload.
Thank you api55
I used metal to do some interpolation task. I wrote the kernel function as followed:
kernel void kf_interpolation( device short *dst, device uchar *src, uint id [[ thread_position_in_grid ]] )
{
dst[id] = src[id-1] + src[id] + src[id+1];
}
That kernel function could not gave expected value. And I found the cause was that the src[id-1] was always 0, which was false value. However, src[id+1] contained the right value. The question is how could I use the neighbour unit correctly, e.g. [id-1], in kernel functions. Thanks in advance.
The most efficient way to handle edge cases like this is usually to grow your source array at each end and offset the indices. So for N calculations, allocate your src array with N+2 elements, fill elements 1 through N (inclusive) with the source data, and set element 0 and N+1 to whatever you want the edge condition to be.
An even more efficient method would be to use MTLTextures instead of MTLBuffers. MTLTextures have an addressing mode attached to them which causes the hardware to automatically substitute either zero or the nearest valid texel when you read off the edge of a texture. They can also do linear interpolation in hardware for free, which can be of great help for resampling, assuming bilinear interpolation is good enough for you. If not, I recommend looking at MPSImageLanczosScale as an alternative.
You can make a MTLTexture from a MTLBuffer. The two will alias the same pixel data.
I have no idea for how to implement matrix implementation efficiently in OpenCV.
I have binary Mat nz(150,600) with 0 and 1 elements.
I have Mat mk(150,600) with double values.
I like to implement as in Matlab as
sk = mk(nz);
That command copy mk to sk only for those element of mk element at the location where nz has 1. Then make sk into a row matrix.
How can I implement it in OpenCV efficiently for speed and memory?
You should take a look at Mat::copyTo and Mat::clone.
copyTo will make an copy with optional mask where its non-zero elements indicate which matrix elements need to be copied.
mk.copyTo(sk, nz);
And if you really want a row matrix then call sk.reshape() as member sansuiso already suggested. This method ...
creates alternative matrix header for the same data, with different
number of channels and/or different number of rows.
bkausbk gave the best answer. However, a second way around:
A=bitwise_and(nz,mk);
If you access A, you can copy the non-zero into a std::vector. If you want your output to be a cv::Mat instance then you have to allocate the memory first:
S=countNonZero(A); //size of the final output matrix
Now, fast element access is an actual topic of itself. Google it. Or have a look at opencv/modules/core/src/stat.cpp where countNonZero() is implemented to get some ideas.
There are two steps involved in your task.
First, you convert to double the input matrix:
cv::Mat binaryMat; // source matrix, filled somewhere
cv::Mat doubleMat; // target matrix (with doubles)
binaryMat.convertTo(doubleMat, CV64F); // Perform the conversion
Then, reshape the result as a row matrix:
doubleMat = cv::reshape(doubleMat, 1, 1);
// Alternatively:
cv::Mat doubleRow = cv::reshape(doubleMat, 1, 1);
The cv::reshape operation is efficient in the sense that the data is not copied, only the structure header changes.
This function returns a new reference to a matrix (by creating a new header), thus you should not forget to assign its result.
I tried to cv::bitwise_not to a cv::Mat matrix of double values. I applied like
cv::bitwise_not(img, imgtemp);
img is CV_64F data of 0 and 1. But imgtemp has all nonsense data inside.
I am expecting 0 in img to be 1 at imgtemp and 1 in img to be 0 at imgtemp. How to apply bitwise_not to a double Mat matrix?
Thanks
I cannot get the sense of doing a bitwise not of a double (floating point) value: you will be doing bitwise operations also on the exponent (see here). All bits will be inverted, from 0 to 1 and viceversa.
There is also a note on this aspect in the function documentation.
In case of a floating-point input array, its machine-specific bit
representation (usually IEEE754-compliant) is used for the operation.
If you want zeros to become ones and viceversa, as you suggested, you could do:
cv::threshold(warpmask, warpmaskTemp,0.5,1.0,THRESH_BINARY_INV)
(see documentation) (and yes, you can use same matrix for input and destination).
I think you are either getting the method signature wrong or wrongly named the parameters for the bitwise_not method.
According to [OpenCV 2.4.6 Documentation on bitwise_not() method] (http://docs.opencv.org/modules/core/doc/operations_on_arrays.html#void bitwise_not(InputArray src, OutputArray dst, InputArray mask))
void bitwise_not(InputArray src, OutputArray dst, InputArray mask=noArray())
If you are going to use any mask, it needs to be the last argument as mask is an optional for 'bitwise_not' method.
Additionally, all the data types need to be the same in order to avoid confusion. What I am trying to imply is that your source and destination data formats and any interim ones such as the method parameters must be in the same format. You cannot have on ein CV_64F and others in different. If I am not loosing my marbles here, bitwise operation would possibly require you to have all the data in unsigned or signed integer format for the sake of simplicity. Nevertheless, you should have all the types same.
About the garbage that you got, I think it is a general and good programming practice that you initialise your variables with some reasonable values. This helps when you are debugging step by step and ascertain the details where it failed.
Give it a try.
To follow on from Antonio's answer, you should use the right tool for the job. double is not an appropriate storage medium for boolean data.
In open cv you can type a boolean as an unsigned char (8bits). Although in typing your own true value you can pick any non-zero value, in open cv it is more natural to have 0/255; that way fitting in with open cv's bitwise operations and comparison operators. E.g. a bitwise not could be achieved by result = (input == 0) which can take any type. threshold in Antonio's answer maintains the same type (useful in some circumstances). For bitwise_not you should have it in the boolean format first.
Unfortunately opencv makes it very difficult to work with black and white bitwise data.