I have a HIK camera that is Onvif compliant. I have been able to get the credentials and login to the camera. From there I am able to create simple rules for cell detection.
I want to add line detection which uses a ItemListElementItem.
I have been reading the specification and documentation This specifically mentions line detection: https://www.onvif.org/specs/srv/analytics/ONVIF-Analytics-Service-Spec.pdf
This document gives some additional overview on the rules: https://www.onvif.org/wp-content/uploads/2016/12/Version_Handling-1.pdf
I can get the supported rules from the device. If I then create a rule from the HIK UI, I have been able to modify this rule with some hard coded string values.
The documentation states that the line "type" should be "polyline" and that this is a "IntRange". I am not sure how to generate the required XMLNode from this information.
Here is the code I have that works, with a generated xmlElement from a string.
public async Task CreateLineDetection()
{
try
{
var device = await OnvifClientFactory.CreateDeviceClientAsync(_cameraIp, _userName, _password);
var media = await OnvifClientFactory.CreateMediaClientAsync(_cameraIp, _userName, _password);
var analyticsEngine = await OnvifClientFactory.CreateAnalyticsEnginePortClientAsync(_cameraIp, _userName, _password);
var ruleEngine = await OnvifClientFactory.CreateRuleEnginePortClientAsync(_cameraIp, _userName, _password);
var profiles = await media.GetProfilesAsync();
var mediaAnalytics = await media.GetVideoAnalyticsConfigurationsAsync();
var analysticConfigurations = mediaAnalytics.Configurations;
var analyticsConfigurationEngine = analysticConfigurations[0].AnalyticsEngineConfiguration;
//get supported rules
var supportedRules = await ruleEngine.GetSupportedRulesAsync(analysticConfigurations[0].token);
if (supportedRules != null)
{
if (supportedRules.RuleDescription != null)
{
foreach (var ruleItem in supportedRules.RuleDescription)
{
Console.WriteLine($"Supported rule is {ruleItem.Name}");
if (ruleItem.Parameters != null)
{
if (ruleItem.Parameters.SimpleItemDescription != null)
{
foreach (var simpleParamItem in ruleItem.Parameters.SimpleItemDescription)
{
Console.WriteLine($"Rule {ruleItem.Name} simple item param name: {simpleParamItem.Name}");
Console.WriteLine($"Rule {ruleItem.Name} simple item param type: {simpleParamItem.Type}");
}
}
if (ruleItem.Parameters.ElementItemDescription != null)
{
foreach (var elementParamItem in ruleItem.Parameters.ElementItemDescription)
{
Console.WriteLine($"Rule {ruleItem.Name} element item param name: {elementParamItem.Name}");
Console.WriteLine($"Rule {ruleItem.Name} element item param type: {elementParamItem.Type}");
}
}
}
}
}
}
//get rule engine from token
var ruleEngineRules = await ruleEngine.GetRulesAsync(analysticConfigurations[0].token);
if (ruleEngineRules != null && ruleEngineRules.Rule != null)
{
//modify existing rule called "MyLineDetector1"
Config[] modifyRule = new Config[1];
modifyRule[0] = ruleEngineRules.Rule.Where(x => x.Name == "MyLineDetector1").FirstOrDefault();
//simple type for the direction. This is magic strings not sure if there is a better way to set this.
Onvif20Analytics.ItemList modifyRuleItems = new Onvif20Analytics.ItemList();
Onvif20Analytics.ItemListSimpleItem modifyRuleSimpleItem1 = new Onvif20Analytics.ItemListSimpleItem();
modifyRuleSimpleItem1.Name = "Direction";
modifyRuleSimpleItem1.Value = "Right";
ItemListElementItem itemListElementItem1 = new ItemListElementItem();
itemListElementItem1.Name = "Segments";
//This is an int range so should be the type for polyline?
IntRange xRange = new IntRange();
xRange.Max = 520;
xRange.Min = 50;
IntRange yRange = new IntRange();
yRange.Max = 520;
yRange.Min = 50;
//string to test value. 1000 is the edge of the screen.
//This is a line from bottom left to top right.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml("<Polyline>" +
"<Point x=\"0.0\" y=\"0.0\"/>" +
"<Point x=\"1000.0\" y=\"1000.0\"/>" +
"</Polyline>");
Console.WriteLine(xmlDoc.DocumentElement.Name);
itemListElementItem1.Any = xmlDoc.DocumentElement;
//after creating items set to the list
modifyRuleItems.SimpleItem = new Onvif20Analytics.ItemListSimpleItem[] { modifyRuleSimpleItem1 };
modifyRuleItems.ElementItem = new ItemListElementItem[] { itemListElementItem1 };
modifyRule[0].Parameters = modifyRuleItems;
//modify rule.
Onvif20Analytics.ModifyRulesResponse ruleUpdateReturned = await ruleEngine.ModifyRulesAsync(profiles.Profiles[0].VideoAnalyticsConfiguration.token, modifyRule);
}
}
catch (Exception ex)
{
}
}
I am not sure how the element items work. They take in a name as a string and then a .Any which is an XMLElement. I am not sure how to generate this or if I am generating the rules correctly.
The specific piece of code I am unsure of in the provided block is:
ItemListElementItem itemListElementItem1 = new ItemListElementItem();
itemListElementItem1.Name = "Segments";
//This is an int range so should be the type for polyline?
IntRange xRange = new IntRange();
xRange.Max = 520;
xRange.Min = 50;
IntRange yRange = new IntRange();
yRange.Max = 520;
yRange.Min = 50;
//string to test value. 1000 is the edge of the screen.
//This is a line from bottom left to top right.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml("<Polyline>" +
"<Point x=\"0.0\" y=\"0.0\"/>" +
"<Point x=\"1000.0\" y=\"1000.0\"/>" +
"</Polyline>");
Console.WriteLine(xmlDoc.DocumentElement.Name);
itemListElementItem1.Any = xmlDoc.DocumentElement;
What I have works but it is hard coded and checking the rule after, it looks subtly different with some tags missing from when I do it within the HIK interface.
Any help would be appreciated.