Skip to content

Call .create() during copyTo for an empty matrix. #21059

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: 3.4
Choose a base branch
from

Conversation

vrabaud
Copy link
Contributor

@vrabaud vrabaud commented Nov 15, 2021

This ensures that the type is copied.
The doc also mentions that .create is called:
https://docs.opencv.org/4.5.4/d3/d63/classcv_1_1Mat.html#a33fd5d125b4c302b0c9aa86980791a77

Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on a code under GPL or other license that is incompatible with OpenCV
  • The PR is proposed to proper branch
  • The feature is well documented and sample code can be built with the project CMake

@alalek
Copy link
Member

alalek commented Nov 15, 2021

Currently, there is no proper support for handling of empty matrices or distinguish them from just declared cv::Mat m;.

AFAIK, meta information should not be used if Mat is .empty().

See also: #7710

@vrabaud
Copy link
Contributor Author

vrabaud commented Nov 16, 2021

I understand we cannot differentiate with a proper empty matrix created by cv::Mat m (which has a default type of CV_8UC1).
Still, behavior is inconsistent: resize(0) keeps the type (cf

void Mat::resize(size_t nelems)
) which makes sense: if you do resize(0) and then resize(1), the type has to be known.

My patch is actually to solve: cv::Mat(0,0,CV_16SC3).clone() returns cv::Mat(0,0,CV_8UC1) (and not an empty matrix of the right type CV_16SC3).

So please advise on how we should fix the following (maybe by just updating the doc in the right places):

I still think my patch would bring some consistency but I would also need to have release() keep the type (which I can add).

@alalek
Copy link
Member

alalek commented Nov 16, 2021

release()

Main point here that "Mat" is a kind of smart pointer over some buffer.
To behave similar to smart pointers, .release() should reset instance to the state of empty and undefined cv::Mat m;.

which contradicts the documentation

Currently it is a gray zone which is not documented.

@vrabaud
Copy link
Contributor Author

vrabaud commented Nov 17, 2021

I agree with .release(), the semantic needs to be clarified in the doc though.

There is actually a way to differentiate between cv::Mat() and cv::Mat(0,0,CV_8U) though their type is 0 for both: elemSize() is 0 in the first case, 1 in the other case.

@vpisarev
Copy link
Contributor

Probably, we should use the check, proposed by @vrabaud (e.g. m.total() == 0 && m.elemSize() == 0) to check for empty matrices and produce meaningful results in this case instead of crashing

@alalek
Copy link
Member

alalek commented Nov 17, 2021

instead of crashing

where is code crashing?


m.elemSize() == 0

Even cv::Mat m; returns 1 here (as its type is CV_8UC1 = 0), so this check doesn't make a lot of sense.

@vrabaud
Copy link
Contributor Author

vrabaud commented Nov 18, 2021

.elemSize() does return different results for me with 4.5.3.

#include "opencv2/core.hpp"
#include <iostream>


int main(int, char**argv){
  cv::Mat m1, m2(0, 0, CV_8U);
  std::cout << m1.elemSize() << " " << m2.elemSize() << std::endl;
}

And

clang++ -l opencv_core -I /usr/include/opencv4/ -o test main.cc
./test
0 1

Maybe we need a .empty() like we have right now that just checks if there are no elements, and a .uninitialized() / .released() / emptyFull() that checks whether we have a cv::Mat() (no element, no type).

@alalek
Copy link
Member

alalek commented Nov 18, 2021

.elemSize()

Right, it has dedicated handling for empty Mat:

size_t Mat::elemSize() const
{
size_t res = dims > 0 ? step.p[dims - 1] : 0;
CV_DbgAssert(res != 0);
return res;
}

I messed that with CV_ELEM_SIZE(flags).

Also please note CV_DbgAssert() check in the code above - using .elemSize() with empty Mat triggers error.

However original expression form m.total() == 0 && m.elemSize() == 0 doesn't make sense.

@vrabaud
Copy link
Contributor Author

vrabaud commented Apr 3, 2024

Hi, what do I do with that PR ? Port it to 4.x or give up until 5.x which has better handling of 0d ?

@vpisarev vpisarev self-requested a review July 25, 2025 07:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants