[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

apps/traincascade/cascadeclassifier.cpp
@@ -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>
@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"

@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.

@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

@vpisarev

vpisarev Dec 19, 2016

Contributor

yes, please

@vpisarev

This comment has been minimized.

Show comment
Hide comment
@vpisarev

vpisarev Dec 19, 2016

Contributor

👍

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