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

[traincascade] add type_id to the old save format #7887

Merged
merged 1 commit into from Dec 19, 2016

Conversation

3 participants
@kevinhughes27
Contributor

kevinhughes27 commented Dec 17, 2016

This pullrequest changes

This PR adds the type_id of opencv-haar-classifier to the saved model when using the latest traincascade program with the -baseFormatSave option.

Background

I recently trained a cascade classifier using the traincascade program with the -baseFormatSave option because I needed to use the GPU version of the classifier for detection. After training when I went to load my cascade.yml file I encountered the following error:

OpenCV Error: Unspecified error (The node does not represent a user object (unknown type?)) in cvRead, file /home/kevin/src/opencv/modules/core/src/persistence.cpp, line 6628
terminate called after throwing an instance of 'cv::Exception'
  what():  /home/kevin/src/opencv/modules/core/src/persistence.cpp:6628: error: (-2) The node does not represent a user object (unknown type?) in function cvRead

I started investigating by looking at the cascades provided by opencv:

new format (from data/haarcascades):

<opencv_storage>
<cascade type_id="opencv-cascade-classifier"><stageType>BOOST</stageType>
  <featureType>HAAR</featureType>
  <height>20</height>
  <width>20</width>
  <stageParams>
  ...
</opencv_storage>

gpu format (from data/haarcascades_gpu):

<opencv_storage>
<haarcascade_frontaleye type_id="opencv-haar-classifier">
  <size>
    20 20</size>
  <stages>
    <_>
      <!-- stage 0 -->
      <trees>
        <_>
          <!-- tree 0 -->
          <_>
            <!-- root node -->
    ...
<opencv_storage>

and compared them to the file that was saved after my classifier was trained:

traincascade with -baseFormatSave option:

<?xml version="1.0"?>
<opencv_storage>
<cascade>
  <size>
    100 40</size>
  <stages>
    <_>
      <trees>
        <_>
          <_>
  ...
<opencv_storage>

This is when I noticed that my output was missing the type_id. Adding this manually fixed the issue and I was able to load and run my classifier. Note that this only affected the old file format and if I saved my classifier in the new format I was able to load it.

From here I started looking into how the classifier is saved to see if I could fix the problem. I am including the notes I took while exploring the FileStorage code in case others find it useful.

  • The traincascade program writes to FileStorage using a hash like DSL starting here
  • The persistence module converts the hash like structure into NODE types. This is how this module is able to support multiple output formats (yml and xml).
  • Here is where the { char is converted to a node by calling cvStartWriteStruct with anything trailing the : as type_name
  • Which writes to type_id here

Testing

There doesn't seem to be any tests for the traincascade app so I wrote a small program to confirm my fix:

#include <opencv2/core/core.hpp>

using namespace cv;

int main() {
  string filename = "cascade.xml";
  FileStorage fs( filename, FileStorage::WRITE );
  fs << FileStorage::getDefaultObjectName(filename) << "{:opencv-haar-classifier";
  fs << "}";
}

which when ran produces:

<?xml version="1.0"?>
<opencv_storage>
<cascade type_id="opencv-haar-classifier"></cascade>
</opencv_storage>

@vpisarev vpisarev self-assigned this Dec 19, 2016

@@ -450,6 +452,7 @@ void CvCascadeClassifier::save( const string filename, bool baseFormat )
CvSeq* weak;
if ( cascadeParams.featureType != CvFeatureParams::HAAR )
CV_Error( CV_StsBadFunc, "old file format is used for Haar-like features only");
fs << "{:" << ICV_HAAR_TYPE_ID;

This comment has been minimized.

@kevinhughes27

kevinhughes27 Dec 19, 2016

Contributor

It was my understanding that the : character was required but I just tried with my test program and it isn't. It does affect the output though - one line vs two lines.

#include <opencv2/core/core.hpp>

using namespace cv;

int main() {
  std::string filename = "cascade.xml";
  FileStorage fs( filename, FileStorage::WRITE );
  fs << FileStorage::getDefaultObjectName(filename) << "{opencv-haar-classifier";
  fs << "}";
}
<?xml version="1.0"?>
<opencv_storage>
<cascade type_id="opencv-haar-classifier">
  </cascade>
</opencv_storage>

This comment has been minimized.

@vpisarev

vpisarev Dec 19, 2016

Contributor

I checked it one more time. fs << "{:" << ICV_HAAR_TYPE_ID; is probably not what you want. You'd want something like fs << "{:" ICV_HAAR_TYPE_ID; to make sure that "{:opencv-haar-classifier" is streamed to fs and parsed as a single "token"

This comment has been minimized.

@kevinhughes27

kevinhughes27 Dec 19, 2016

Contributor

That makes sense I was wondering about that as well since one of my earlier tests did't work as expected but then they all started to. I can make the change.

This comment has been minimized.

@vpisarev

vpisarev Dec 19, 2016

Contributor

yes, please

@kevinhughes27 kevinhughes27 force-pushed the kevinhughes27:traincascade-baseformat-fix branch from a403bee to 0d32bec Dec 19, 2016

@vpisarev

This comment has been minimized.

Contributor

vpisarev commented Dec 19, 2016

👍

@opencv-pushbot opencv-pushbot merged commit 0d32bec into opencv:master Dec 19, 2016

1 check passed

default Required builds passed
Details
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment