I am somewhat new to SVMs and object recognition, and am currently attempting to train an SVM using Emgu CV 3.0, save it to a file, and then load it (for use in HOGDescriptor.SetSVMDetector).
However, among other problems, I cannot find a way to load the SVM after I have saved it.
So far, my code basically does the following:
SVM myFirstSVM = new SVM();
// do some stuff, set some parameters...
myFirstSVM.Train(someParameters);
myFirstSVM.Save("filePath");
From here, the problem lies with reloading the SVM after being saved. I have checked several help topics and pages, and the only related things I could find pertained to OpenCV, which used the following method:
SVM mySecondSVM;
mySecondSVM.load("filePath");
However, I could find no method ".load()" in Emgu 3.0, although it appeared to be present in previous versions. Is there an equivalent of this OpenCV method in Emgu 3.0? I would assume there is, and I am sure it is fairly simple, but I cannot for the life of me find it.
For EmguCV 3.0.0, the Save/Load functionality doesn't seem to be supported (Load doesn't exist), you could use Write/Read instead.
A function to save an SVM model:
public static void SaveSVMToFile(SVM model, String path) {
if (File.Exists(path)) File.Delete(path);
FileStorage fs = new FileStorage(path, FileStorage.Mode.Write);
model.Write(fs);
fs.ReleaseAndGetString();
}
A function to load the SVM model provided the correct path:
public static SVM LoadSVMFromFile(String path) {
SVM svm = new SVM();
FileStorage fs = new FileStorage(path, FileStorage.Mode.Read);
svm.Read(fs.GetRoot());
fs.ReleaseAndGetString();
return svm;
}
I have saved and read the SVM model using the specified functions. But I am working with 3.1.0 version and hope it works for you as well:
I have saved the model in an XML file because the read function works on xml file as far as I know:
Emgu.CV.ML.SVM model = new Emgu.CV.ML.SVM();
model.SetKernel(Emgu.CV.ML.SVM.SvmKernelType.Linear);
model.Type = Emgu.CV.ML.SVM.SvmType.CSvc;
model.C = 1;
model.TermCriteria = new MCvTermCriteria(100, 0.00001);
bool trained = model.TrainAuto(my_trainData, 5);
model.Save("SVM_Model.xml");
and I read the model as follows:
Emgu.CV.ML.SVM model_loaded = new Emgu.CV.ML.SVM();
FileStorage fsr = new FileStorage("SVM_Model.xml", FileStorage.Mode.Read);
model_loaded.Read(fsr.GetFirstTopLevelNode());
and it works correctly.
I hope it works for you so.
For EmguCV 1.5.0:
Load Method (fileName):
Inherited from StatModel
Load the statistic model from file
fileName (String)
The file to load the model from
For EmguCV 3.0+:
Load() is not available, as you can see in the source code: https://sourceforge.net/p/emgucv/code/ci/master/tree/Emgu.CV.ML/StatModel.cs
Related
we are trying to add parameters to a transformation at the runtime. The only possible way to do so, is to set every single parameter and not a node. We don't know yet how to create a node for the setParameter.
Current setParameter:
QName TEST XdmAtomicValue 24
Expected setParameter:
<TempNode> <local>Value1</local> </TempNode>
We searched and tried to create a XdmNode and XdmItem.
If you want to create an XdmNode by parsing XML, the best way to do it is:
DocumentBuilder db = processor.newDocumentBuilder();
XdmNode node = db.build(new StreamSource(
new StringReader("<doc><elem/></doc>")));
You could also pass a string containing lexical XML as the parameter value, and then convert it to a tree by calling the XPath parse-xml() function.
If you want to construct the XdmNode programmatically, there are a number of options:
DocumentBuilder.newBuildingStreamWriter() gives you an instance of BuildingStreamWriter which extends XmlStreamWriter, and you can create the document by writing events to it using methods such as writeStartElement, writeCharacters, writeEndElement; at the end call getDocumentNode() on the BuildingStreamWriter, which gives you an XdmNode. This has the advantage that XmlStreamWriter is a standard API, though it's not actually a very nice one, because the documentation isn't very good and as a result implementations vary in their behaviour.
Another event-based API is Saxon's Push class; this differs from most push-based event APIs in that rather than having a flat sequence of methods like:
builder.startElement('x');
builder.characters('abc');
builder.endElement();
you have a nested sequence:
Element x = Document.elem('x');
x.text('abc');
x.close();
As mentioned by Martin, there is the "sapling" API: Saplings.doc().withChild(elem(...).withChild(elem(...)) etc. This API is rather radically different from anything you might be familiar with (though it's influenced by the LINQ API for tree construction on .NET) but once you've got used to it, it reads very well. The Sapling API constructs a very light-weight tree in memory (hance the name), and converts it to a fully-fledged XDM tree with a final call of SaplingDocument.toXdmNode().
If you're familiar with DOM, JDOM2, or XOM, you can construct a tree using any of those libraries and then convert it for use by Saxon. That's a bit convoluted and only really intended for applications that are already using a third-party tree model heavily (or for users who love these APIs and prefer them to anything else).
In the Saxon Java s9api, you can construct temporary trees as SaplingNode/SaplingElement/SaplingDocument, see https://www.saxonica.com/html/documentation12/javadoc/net/sf/saxon/sapling/SaplingDocument.html and https://www.saxonica.com/html/documentation12/javadoc/net/sf/saxon/sapling/SaplingElement.html.
To give you a simple example constructing from a Map, as you seem to want to do:
Processor processor = new Processor();
Map<String, String> xsltParameters = new HashMap<>();
xsltParameters.put("foo", "value 1");
xsltParameters.put("bar", "value 2");
SaplingElement saplingElement = new SaplingElement("Test");
for (Map.Entry<String, String> param : xsltParameters.entrySet())
{
saplingElement = saplingElement.withChild(new SaplingElement(param.getKey()).withText(param.getValue()));
}
XdmNode paramNode = saplingElement.toXdmNode(processor);
System.out.println(paramNode);
outputs e.g. <Test><bar>value 2</bar><foo>value 1</foo></Test>.
So the key is to understand that withChild() returns a new SaplingElement.
The code can be compacted using streams e.g.
XdmNode paramNode2 = Saplings.elem("root").withChild(
xsltParameters
.entrySet()
.stream()
.map(p -> Saplings.elem(p.getKey()).withText(p.getValue()))
.collect(Collectors.toList())
.toArray(SaplingElement[]::new))
.toXdmNode(processor);
System.out.println(paramNode2);
I've got a network trained and I want to save it and be able to load it later so I don't have to re-train it... duh.
End of training code:
//Save network
SerializeObject.save(new File("encognet"),network);
Encog.getInstance().shutdown();
Loading File
BasicNetwork network = (BasicNetwork) EncogDirectoryPersistence.loadObject(new File("encognet"));
I get this error
Exception in thread "main" org.encog.persist.PersistError: Not a valid
EG file.
Can anyone tell me how to fix this?
I think the problem is that you are not saving the file as an .eg extension. If this is not the problem, I'm not sure about SerializeObject.save, but I know that EncogDirectoryPersistence works for me.
So, test out this code for saving
public static final String FILENAME = "test_load_net.eg";
EncogDirectoryPersistence.saveObject(new File(FILENAME), network);
And then load like this
public static final String FILENAME = "test_load_net.eg";
BasicNetwork network = (BasicNetwork)EncogDirectoryPersistence.loadObject(new File(FILENAME));
I'm basically reading several fields in an OpenCV FileNode, doing some calculations, and then replacing just one of the fields in the original OpenCV FileNode with the calculated data.
I can't find any methods that allow me to do this. Has anyone done this before?
Thanks for your help!
After some searching, it appears that I cannot append or add to an existing filenode or filestorage object.
However, what you can do is create a new FileStorage object, copy over any existing FileNodes you may want to keep, discard any old fields you do not want, and then save this new FileStorage object with the updated data.
I couldn't find a way to use the latest C++ interface to copy FileNodes, however, I did find a way to use the old deprecated structures to accomplish this. The following will copy mapped FileNode to a new FileStorage object.
cv::FileStorage fileStructure;
fileStructure.open("yourfile.xml", cv::FileStorage::WRITE);
CvFileStorage* fsPtr= fileStructure.operator *(); //gets the underlying pointer
cvWriteFileNode(fsPtr, "CopiedNode", fileNodeObject.operator *(),0);
I hope this helps people who are stuck like I was.
Best,
Paul
In OpenCV 4.0, there is a member function of FileNode
void setValue (int type, const void *value, int len=-1);
I haven't try, but it seems to design for this.
There seems not to be any official way to do this prior OpenCV 4.x. A workaround is to use the underlying basic element:
//type int with value of 5
cv::FileNode node;
CvFileNode* rawNode = *node;
//now the new value is 6
rawNode->data.i = 6;
For Testing purposes I'm trying to design a way to verify that the results of statistical tests are identical across versions, platforms and such. There are a lot things that go on that include ints, nums, dates, Strings and more inside our collections of Objects.
In the end I want to 'know' that the whole set of instantiated objects sum to the same value (by just doing something like adding the checkSum of all internal properties).
I can write low level code for each internal value to return a checkSum but I was thinking that perhaps something like this already exists.
Thanks!
_swarmii
This sounds like you should be using the serialization library (install via Pub).
Here's a simple example to get you started:
import 'dart:io';
import 'package:serialization/serialization.dart';
class Address {
String street;
int number;
}
main() {
var address = new Address()
..number = 5
..street = 'Luumut';
var serialization = new Serialization()
..addRuleFor(address);
Map output = serialization.write(address, new SimpleJsonFormat());
print(output);
}
Then depending on what you want to do exactly, I'm sure you can fine tune the code for your purpose.
I have an EMGU (openCV wrapper) program that subtracts the background from
a camera feed and extracts nice clean blobs.
Now I need something that will track these blobs and assign them with IDs.
Any suggestions/libraries ?
Thanks,
SW
well if you have multiple objects that you would like to track you could try a Particle Filter.
Particle filters basically "disposes" particles on the image which each have a certain weight. In each time step these weights are then updated by comparing them with the actual measured value of the object at that time. Particles with high weight will then dispose more particles in its direction (with adding a slight random part on the direction) for the next time step.
After a few time steps the particles will then group around the objects measured position. That's why this method is sometimes also called Survival of the fittest method...
So this whole thing builds a circle:
Initialization ----> Sampling
> \
/ >
Updating Prediction
< /
\ <
Association
So this provides a good method of tracking objects in a given scene. One way to do multi-object tracking would be to use this one particle filter on all the objects, which would work, but has disadvantages when you try to give IDs to the objects and also when the objects cross each other since the particle clouds might lose one object and follow another one.
To solve this you could try a Mixture-Particle-Filter (by Vermaak et al. [2003]). This one tracks each of the objects by an individual Particle filter (with of course less necessary particles).
A good paper on that can be found here: http://www.springerlink.com/content/qn4704415gx65315/
(I can also supply you with several other stuff on that if you like and if you speak German I can even give you a presentation I held about that in my university a while ago)
EDIT:
Forgot to mention: Since you try to do this in OpenCV: as far as I know there is an implementation of the Condensation algorithm (the first one where you use one particle filter on the whole image) is part of the OpenCV distribution, though it might be outdated a bit. There might be newer ways of the particle filter in OpenCV directly but if not you will find a lot of results on Google if you look for OpenCV and particle filters
Hope that helps... if not, please keep asking...
You could simply adapt one of the EMGU CV examples that makes use of
VideoSurveillance namespace:
public partial class VideoSurveilance : Form
{
private static MCvFont _font = new MCvFont(Emgu.CV.CvEnum.FONT.CV_FONT_HERSHEY_SIMPLEX, 1.0, 1.0);
private static Capture _cameraCapture;
private static BlobTrackerAuto<Bgr> _tracker;
private static IBGFGDetector<Bgr> _detector;
public VideoSurveilance()
{
InitializeComponent();
Run();
}
void Run()
{
try
{
_cameraCapture = new Capture();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
return;
}
_detector = new FGDetector<Bgr>(FORGROUND_DETECTOR_TYPE.FGD);
_tracker = new BlobTrackerAuto<Bgr>();
Application.Idle += ProcessFrame;
}
void ProcessFrame(object sender, EventArgs e)
{
Image<Bgr, Byte> frame = _cameraCapture.QueryFrame();
frame._SmoothGaussian(3); //filter out noises
#region use the background code book model to find the forground mask
_detector.Update(frame);
Image<Gray, Byte> forgroundMask = _detector.ForgroundMask;
#endregion
_tracker.Process(frame, forgroundMask);
foreach (MCvBlob blob in _tracker)
{
frame.Draw(Rectangle.Round(blob), new Bgr(255.0, 255.0, 255.0), 2);
frame.Draw(blob.ID.ToString(), ref _font, Point.Round(blob.Center), new Bgr(255.0, 255.0, 255.0));
}
imageBox1.Image = frame;
imageBox2.Image = forgroundMask;
}
}