Wednesday, April 11, 2012

Creating a templated Binary Search Tree Class in C++

Creating a basic template Tree Class in C++
(Works in Linux and Windows)

If you just want the code and not the walkthrough, it is attached at the end (I use the GNU GPL license, so do whatever you want with the code as long as you mention me).

There a multiple benefits of creating a Tree class based on a template. With a template, the tree can be a container for anything while still being fairly clean code. We will also create this class to be easily inherited for other trees such as an AVL and Huffman tree (which we will implement later).

A tree is a widely used data structure which organizes a set of nodes containing data. More can be found on it here: http://en.wikipedia.org/wiki/Tree_%28data_structure%29

This tree will be a Binary Search Tree; however, it will be easily inheritable so that other trees (Binary trees, such as AVL and Red-Black) can be defined based on it.

First we will set up our Node as a holder for the data and tree information such as the parent and connected nodes (the leaves). I overload the < operator so that we can search and sort this tree using the c++ algorithm include if we so desire.

template <class T>
class Node {
public:
    T data;
    Node *left, *right, *parent;

    Node() {
        left = right = parent = NULL;
    };
    Node(T &value) {
        data = value;
    };
    ~Node() {
    };   
    void operator= (const Node<T> &other) {
        data = other.data;
    };
    bool operator< (T &other) {
        return (data < other);
    };
};

Our tree will basically just be a bunch of these Nodes pointing to each other, with some functions to manage the data structure.

template <class T>
class Tree {
public:
    Tree() {
        root = NULL;
    };

    ~Tree() {
        m_destroy(root);
    };

    //We will define these all as virtuals for inherited trees (like a Huffman Tree and AVL Tree shown later)
    virtual void insert(T &value) {
        m_insert(root,NULL,value);
    };
    virtual Node<T>* search(T &value) {
        return m_search(root,value);
    };
    virtual bool remove(T &value) {
        return m_remove(root,value);
    };
    virtual bool operator< (Tree<T> &other) {
        return (root->data < other.first()->data);
    };
    void operator= (Tree<T> &other) {
        m_equal(root,other.first());
    };
    Node<T>*& first() {
        return root;
    };


protected:
    //this will be our root node and private functions
    Node<T> *root;
    void m_equal(Node<T>*& node, Node<T>* value) {
        if(value != NULL) {
            node = new Node<T>();
            *node = *value;
            if(value->left != NULL)
                m_equal(node->left, value->left);
            if(value->right != NULL)
                m_equal(node->right, value->right);
        }
    }

    void m_destroy(Node<T>* value) {
        if(value != NULL) {
            m_destroy(value->left);
            m_destroy(value->right);
            delete value;
        }
    };
    void m_insert(Node<T> *&node, Node<T> *parent, T &value) {
        if(node == NULL) {
            node = new Node<T>();
            *node = value;
            node->parent = parent;
        } else if(value < node->data) {
            m_insert(node->left,node,value);
        } else
            m_insert(node->right,node,value);
    };
    void m_insert(Node<T> *&node, Node<T> *parent, Tree<T> &tree) {
        Node<T> *value = tree.first();
        if(node == NULL) {
            node = new Node<T>();
            *node = *value;
            node->parent = parent;
        } else if(value->data < node->data) {
            m_insert(node->left,tree);
        } else
            m_insert(node->right,tree);
    };
    Node<T>* m_search(Node<T> *node, T &value) {
        if(node == NULL)
            return NULL;
        else if(value == node->data)
            return node;
        else if(value < node->data)
            return m_search(node->left,value);
        else
            return m_search(node->right,value);
    };

    bool m_remove(Node<T> *node, T &value) {
        //messy, need to speed this up later
        Node<T> *tmp = m_search(root,value);
        if(tmp == NULL)
            return false;
        Node<T> *parent = tmp->parent;
        //am i the left or right of the parent?
        bool iamleft = false;
        if(parent->left == tmp)
            iamleft = true;
        if(tmp->left != NULL && tmp->right != NULL) {
            if(parent->left == NULL || parent->right == NULL) {
                parent->left = tmp->left;
                parent->right = tmp->right;
            } else {
                if(iamleft)
                    parent->left = tmp->left;
                else
                    parent->right = tmp->left;
                T data = tmp->right->data;
                delete tmp;
                m_insert(root,NULL,data);
            }
        } else if(tmp->left != NULL) {
            if(iamleft)
                parent->left = tmp->left;
            else
                parent->right = tmp->left;
        } else if(tmp->right != NULL ) {
            if(iamleft)
                parent->left = tmp->right;
            else
                parent->right = tmp->right;
        } else {
            if(iamleft)
                parent->left = NULL;
            else
                parent->right = NULL;
        }
        return true;
    };
};

And that's all we need for a basic binary search tree. The full code is shown below

Tree.h 

Consider donating to further my tinkering.


Places you can find me

Monday, April 9, 2012

How to determine how many cameras are connected to a computer and connect to and use ptz cameras

How to determine how many cameras are connected to a computer and connect to and use ptz cameras:

I figure this is a nice easy first post. This is some code I struggled with finding a couple years ago on automatically determining how many cameras are connected to a computer via directshow (this code is also useful in a ptz application as I will show right after). I use OpenCV to capture from the camera and the directshow library to use the ptz camera functions. I also used the vector and stringstream library for my own ease (#include<vector> #include<sstream>)

The DisplayError function is a generic wrapper for you to fill in, whether you use printf or a messagebox.

int getDeviceCount() {
  try {
    ICreateDevEnum *pDevEnum = NULL;
    IEnumMoniker *pEnum = NULL;
    int deviceCounter = 0;
    HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, reinterpret_cast<void**>(&pDevEnum));
    if (SUCCEEDED(hr)) {
      // Create an enumerator for the video capture category.
      hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);
      if (hr == S_OK) {
        IMoniker *pMoniker = NULL;
        while (pEnum->Next(1, &pMoniker, NULL) == S_OK) {
          IPropertyBag *pPropBag;
          hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)(&pPropBag));
          if (FAILED(hr)) {
            pMoniker->Release();
            continue; // Skip this one, maybe the next one will work.
          }
          pPropBag->Release();
          pPropBag = NULL;
          pMoniker->Release();
          pMoniker = NULL;
          deviceCounter++;
        }
        pEnum->Release();
        pEnum = NULL;
      }
      pDevEnum->Release();
      pDevEnum = NULL;
    }
    return deviceCounter;
  } catch(Exception & e) {
    DisplayError(e.ToString());
  } catch(...) {
    DisplayError("Error Caught Counting # of Devices");
  }
  return 0;
}


This can easily be modified to connect to x number of ptz cameras with a quick ptz class

Here is our ptz class:

class ptz {
public:
  struct controlVals {
  public:
    long min, max, step, def, flags;
  };
  IBaseFilter *filter;
  IAMCameraControl *camControl;

  bool valid, validMove;
  CvCapture *capture;
  bool Initialize() {
    camControl = NULL;
    controlVals panInfo = {0}, tiltInfo = {0};
    HRESULT hr = filter->QueryInterface(IID_IAMCameraControl, (void **)&camControl);
    if(hr != S_OK)
      return false;
    else
      return true;
  }

  void ptz(int instance) {

    threadNum = instance;
    // sets up a continuous capture point through the msvc driver
    capture = cvCaptureFromCAM(threadNum);
    if (!capture)
      valid = false;
    else
      valid = true;

  }
  void Destroy() {
    if(camControl) {
      camControl->Release();
      camControl = NULL;
    }
    if (filter) {
      filter->Release();
      filter = NULL;
    }
  }
};


And here is the modified getDeviceCount code which now connects to all the cameras and gets the ptz information using direct show:

int getDeviceCount(vector<ptz> &cameras) {
  try {
    ICreateDevEnum *pDevEnum = NULL;
    IEnumMoniker *pEnum = NULL;
    int deviceCounter = 0;

    HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, reinterpret_cast<void**>(&pDevEnum));
    if (SUCCEEDED(hr)) {
      // Create an enumerator for the video capture category.
      hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);
      if (hr == S_OK) {
        IMoniker *pMoniker = NULL;
        do {
          if (pEnum->Next(1, &pMoniker, NULL) == S_OK) {
            IPropertyBag *pPropBag;
            hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)(&pPropBag));
            if (FAILED(hr)) {
              pMoniker->Release();
              continue; // Skip this one, maybe the next one will work.
            }
            if (SUCCEEDED(hr)) {
              ptz tmp = ptz(deviceCounter);
              HRESULT hr2 = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**) & (tmp.filter));
              if (tmp.valid)
                tmp.validMove = tmp.Initialize();
            }
            pPropBag->Release();
            pPropBag = NULL;
            pMoniker->Release();
            pMoniker = NULL;
            deviceCounter++;
          } else {
            ptz tmp = ptz(deviceCounter);
            cameras.push_back(tmp);
            deviceCounter++;
            break;
          }
        }
        while (cameras[deviceCounter -1].valid);
        pEnum->Release();
        pEnum = NULL;
      }
      pDevEnum->Release();
      pDevEnum = NULL;
    }
    return deviceCounter;
  } catch(Exception & e) {
    DisplayError(e.ToString());
  } catch(...) {
    DisplayError("Error Caught Counting # of Devices");
  }
  return 0;
}


Notice now how we have integrated OpenCV into our ptz class. Now as we find cameras we can capture the camera information using OpenCV and then use directshow to grab the information used for ptz. To move the camera we can use  a pan and a tilt function like the following:

HRESULT MechanicalPan(IAMCameraControl *pCameraControl, long value) {
  HRESULT hr = 0;
  try {
    long flags = KSPROPERTY_CAMERACONTROL_FLAGS_RELATIVE | KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
    hr = pCameraControl->Set(CameraControl_Pan, value, flags);
    if (hr == 0x800700AA)
      Sleep(1);
    else if (hr != S_OK && hr != 0x80070490) {
      stringstream tmp;
      tmp << "ERROR: Unable to set CameraControl_Pan property value to " << value << ". (Error " << std::hex << hr << ")";
      throw Exception(tmp.str().c_str());
    }
    // Note that we need to wait until the movement is complete, otherwise the next request will
    // fail with hr == 0x800700AA == HRESULT_FROM_WIN32(ERROR_BUSY).
  } catch(Exception & e) {
    DisplayError(e.ToString());
  } catch(...) {
    DisplayError("Error Caught panning camera");
  }
  return hr;
}
// ----------------------------------------------------------------------------
HRESULT MechanicalTilt(IAMCameraControl *pCameraControl, long value) {
  HRESULT hr = 0;
  try {
    long flags = KSPROPERTY_CAMERACONTROL_FLAGS_RELATIVE | KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
    hr = pCameraControl->Set(CameraControl_Tilt, value, flags);
    if (hr == 0x800700AA)
      Sleep(1);
    else if (hr != S_OK && hr != 0x80070490) {
      stringstream tmp;
      tmp << "ERROR: Unable to set CameraControl_Tilt property value to " << value << ". (Error " << std::hex << hr << ")";
      throw Exception(tmp.str().c_str());
    }
    // Note that we need to wait until the movement is complete, otherwise the next request will
    // fail with hr == 0x800700AA == HRESULT_FROM_WIN32(ERROR_BUSY).
  } catch(Exception & e) {
    DisplayError(e.ToString());
  } catch(...) {
    DisplayError("Error Caught tilting camera");
  }
  return hr;
}




Consider donating to further my tinkering.


Places you can find me