void RectangleExpositor::calculate(Image & evaluation, JSON & data) { int numberOfChanges = 0; Rectangle rectangle(evaluation.getColumns(), evaluation.getRows(), 0, 0); // ----------------------------------- // loop over image and detect changes for(int i = m_x1; i < m_x2; i++) { for(int j = m_y1; j < m_y2; j++) { if(static_cast<int>(evaluation.get(j,i)) == 255) { numberOfChanges++; if(rectangle.m_x1>i) rectangle.m_x1 = i; if(rectangle.m_x2<i) rectangle.m_x2 = i; if(rectangle.m_y1>j) rectangle.m_y1 = j; if(rectangle.m_y2<j) rectangle.m_y2 = j; } } } // ------------------------- //check if not out of bounds if(rectangle.m_x1-10 > 0) rectangle.m_x1 -= 10; if(rectangle.m_y1-10 > 0) rectangle.m_y1 -= 10; if(rectangle.m_x2+10 < evaluation.getColumns()-1) rectangle.m_x2 += 10; if(rectangle.m_y2+10 < evaluation.getRows()-1) rectangle.m_y2 += 10; // -------------------------- // Add coordinates to object JSON::AllocatorType& allocator = data.GetAllocator(); JSONValue region; region.SetArray(); region.PushBack(rectangle.m_x1, allocator); region.PushBack(rectangle.m_y1, allocator); region.PushBack(rectangle.m_x2, allocator); region.PushBack(rectangle.m_y2, allocator); data.AddMember("regionCoordinates", region, allocator); // -------------------------- // Add number of changes if(numberOfChanges) { LINFO << "RectangleExpositor: activity detected from (" + helper::to_string(rectangle.m_x1) + "," + helper::to_string(rectangle.m_y1) + ") to (" + helper::to_string(rectangle.m_x2) + "," + helper::to_string(rectangle.m_y2) + ")"; } data.AddMember("numberOfChanges", numberOfChanges, allocator); }
bool IoWebhook::save(Image & image, JSON & data) { // --------------------------------------- // Attach additional fields to JSON object JSON dataCopy; JSON::AllocatorType& allocator = dataCopy.GetAllocator(); dataCopy.CopyFrom(data, allocator); JSONValue instanceName; instanceName.SetString(getInstanceName().c_str(), allocator); dataCopy.AddMember("instanceName", instanceName, allocator); // ----------------------------- // Convert JSON object to string rapidjson::StringBuffer buffer; rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); dataCopy.Accept(writer); // ------------------- // Send a post to URL BINFO << "IoWebhook: post to webhook " + (std::string) getUrl(); RestClient::response r = RestClient::post(getUrl(), "application/json", buffer.GetString()); if(r.code == 200) { return true; } return false; }
bool IoDisk::save(Image & image, JSON & data) { // ---------------------------------------- // The naming convention that will be used // for the image. std::string pathToImage = getFileFormat(); // ------------------------------------------ // Stringify data object: build image path // with data information. static const std::string kTypeNames[] = { "Null", "False", "True", "Object", "Array", "String", "Number" }; for (JSONValue::ConstMemberIterator itr = data.MemberBegin(); itr != data.MemberEnd(); ++itr) { std::string name = itr->name.GetString(); std::string type = kTypeNames[itr->value.GetType()]; if(type == "String") { std::string value = itr->value.GetString(); kerberos::helper::replace(pathToImage, name, value); } else if(type == "Number") { std::string value = kerberos::helper::to_string(itr->value.GetInt()); kerberos::helper::replace(pathToImage, name, value); } else if(type == "Array") { std::string arrayString = ""; for (JSONValue::ConstValueIterator itr2 = itr->value.Begin(); itr2 != itr->value.End(); ++itr2) { type = kTypeNames[itr2->GetType()]; if(type == "String") { arrayString += itr2->GetString(); } else if(type == "Number") { arrayString += kerberos::helper::to_string(itr2->GetInt()); } arrayString += "-"; } kerberos::helper::replace(pathToImage, name, arrayString.substr(0, arrayString.size()-1)); } } /// --------------------- // Replace variables pathToImage = buildPath(pathToImage); // ------------------------------------------------------- // Add path to JSON object, so other IO devices can use it JSONValue path; JSON::AllocatorType& allocator = data.GetAllocator(); path.SetString(pathToImage.c_str(), allocator); data.AddMember("pathToImage", path, allocator); // ------------------ // Draw date on image drawDateOnImage(image, data["timestamp"].GetString()); // ------------------------- // Save original version BINFO << "IoDisk: saving image " + pathToImage; return m_fileManager.save(image, pathToImage); }
bool Counter::isValid(const Image & evaluation, const ImageVector & images, JSON & data) { int numberOfChanges; Rectangle rectangle; numberOfChanges = data["numberOfChanges"].GetInt(); int incoming = 0; int outgoing = 0; kerberos::Image image = evaluation; cv::Mat img = image.getImage(); cv::dilate(img, img, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(25,25))); cv::erode(img, img, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(10,10))); cv::Point & outTop = m_out[0]; cv::Point & outBottom = m_out[1]; cv::Point & inTop = m_in[0]; cv::Point & inBottom = m_in[1]; std::vector<std::vector<cv::Point> > contours; std::vector<cv::Vec4i> hierarchy; cv::findContours(image.getImage(), contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE); int numberOfContours= 0; for(int i = 0; i < m_features.size(); i++) { int mostRecent = m_features[i].size() - 1; m_features[i][mostRecent].decreaseAppearance(); } // Find new tracks if(contours.size() > 0) { for( int i = 0; i< contours.size(); i++ ) { cv::Moments moments = cv::moments(contours[i]); int x = moments.m10/moments.m00; int y = moments.m01/moments.m00; int area = cv::contourArea(contours[i]); if(area < m_minArea) continue; Feature current(x, y, area, m_appearance); int best = -1; double bestValue = 99999999; double bestArea = 99999999; for(int j = 0; j < m_features.size(); j++) { int mostRecent = m_features[j].size() - 1; double distance = current.distance(m_features[j][mostRecent]); double areaDistance = current.areaDistance(m_features[j][mostRecent]); if(distance < m_maxDistance && distance < bestValue + m_maxDistance/2) { if(areaDistance < bestArea) { best = j; bestValue = distance; } } } if(best == -1) { std::vector<Feature> tracking; tracking.push_back(current); m_features.push_back(tracking); } else { m_features[best].push_back(current); } numberOfContours++; } } // Remove old tracks std::vector<std::vector<Feature> >::iterator it = m_features.begin(); while(it != m_features.end()) { Feature & back = it->back(); back.decreaseAppearance(); if(back.getAppearance() < 0) { it = m_features.erase(it); } else { it++; } } // Check existing tracks if they crossed the line it = m_features.begin(); while(it != m_features.end()) { if(it->size() > 1) { for(int j = 1; j < it->size(); j++) { cv::Point2f prev((*it)[j-1].getX(),(*it)[j-1].getY()); cv::Point2f curr((*it)[j].getX(),(*it)[j].getY()); } // Check if cross line cv::Point2f start((*it)[0].getX(),(*it)[0].getY()); cv::Point2f end((*it)[it->size()-1].getX(),(*it)[it->size()-1].getY()); // Check if interset in line cv::Point2f intersectionPointOutgoing; bool inLine = false; if(intersection(start, end, outTop, outBottom, intersectionPointOutgoing)) { inLine = true; } // Check if interset out line cv::Point2f intersectionPointIncoming; bool outLine = false; if(intersection(start, end, inTop, inBottom, intersectionPointIncoming)) { outLine = true; } // Check if interesected both Direction xDirection = parallell; Direction yDirection = parallell; if(inLine && outLine) { // What is the direction (incoming our outgoing?) if(start.x - end.x < 0) { xDirection = right; } else if(start.x - end.x > 0) { xDirection = left; } if(start.y - end.y < 0) { yDirection = bottom; } else if(start.y - end.y > 0) { yDirection = top; } // Check which intersection point comes first if(xDirection != parallell) { if(xDirection == left) { // Check which intersection point is most right; if(intersectionPointIncoming.x > intersectionPointOutgoing.x) { incoming++; } else { outgoing++; } } else if(xDirection == right) { // Check which intersection point is most right; if(intersectionPointIncoming.x < intersectionPointOutgoing.x) { incoming++; } else { outgoing++; } } } else { } it = m_features.erase(it); } else { it++; } } else { it++; } } if(numberOfChanges >= m_minimumChanges) { JSON::AllocatorType& allocator = data.GetAllocator(); data.AddMember("incoming", incoming, allocator); data.AddMember("outgoing", outgoing, allocator); if(m_onlyTrueWhenCounted) { if(incoming > 0 || outgoing > 0) { BINFO << "Counter: in (" << helper::to_string(incoming) << "), out (" << helper::to_string(outgoing) << ")"; return true; } } else { return true; } } else { usleep(m_noMotionDelayTime*1000); } return false; }
TEST(SEQUENCE_HEURISTIC, IS_VALID) { Heuristic * heuristic = Factory<Heuristic>::getInstance()->create("Sequence"); StringMap settings; settings["heuristics.Sequence.minimumChanges"] = "1"; settings["heuristics.Sequence.minimumDuration"] = "2"; settings["heuristics.Sequence.motionDelayTime"] = "1000"; settings["heuristics.Sequence.noMotionDelayTime"] = "1000"; heuristic->setup(settings); // ---------------------------- // Mocking image Image image; ImageVector images; JSON json; JSON::AllocatorType& allocator = json.GetAllocator(); json.SetObject(); json.AddMember("numberOfChanges", 0, allocator); // -------------------- // Nothing changed thus false. bool isValid = heuristic->isValid(image, images, json); EXPECT_EQ(false, isValid); // --------------------- // Changed, but this is only the first occurence thus again false. json.RemoveMember ("numberOfChanges"); json.AddMember("numberOfChanges", 1, allocator); isValid = heuristic->isValid(image, images, json); EXPECT_EQ(false, isValid); // --------------------- // Changed and the second occurence thus true. isValid = heuristic->isValid(image, images, json); EXPECT_EQ(true, isValid); }