555

94 lines
6.8 KiB

  1. \section{Data Size Decision Framework}
  2. \label{sec:design}
  3. This section presents the proposed method to outcome a data array than have less size compare to jpeg image when we can tolerate some error of data. We use the image captured by FLIR ONE PRO. In a thermal image, the temperature variation between nearby pixels are very small except the edge of objects. Hence, we can separate an image into several regions, and the pixels in a same region has similar value so we can use the average value to represent it and do not cause too much error. However, precisely separate an image into some polygon region takes a lot of computation time and hard to describe the edge of each region. Also, decide the number of region also a problem. Hence, to effectively describe regions we design that every region most be a rectangle, and every region can only separate into 4 regions by cut in half at the middle of horizontal and vertical. The image will start from only contains one region, and 3 regions will be added per round since we cut a region into 4 pieces.
  4. \subsection{Region Represent Grammar}
  5. For each frame, we can use a context-free language to represent it.
  6. \begin{center}
  7. \begin{tabular}{rl}
  8. $S \rightarrow\ $ & $R$ \\
  9. $R \rightarrow\ $ & $\alpha$\\
  10. $R \rightarrow\ $ & $\beta RRRR$
  11. \end{tabular}
  12. \end{center}
  13. $R$ means a region of image, and it can either use the average $\alpha$ of the pixels in the region to represent whole region or separate into four regions and left a remainder $\beta$. Dependence on the image size we desired, we can choose the amount of separating regions.
  14. The context-free grammar start from a region contain whole image. For each $R$ we calculate a score which is based on the quality of data we can improve by separate it in to smaller regions. After some operation, we can encode the image into a string $\omega$. Figure~\ref{fig:pngImage} shows an example of image which was took by FLIR ONE PRO. One of the possible outcome is Figure~\ref{fig:SeparateImage} if we separate the image 6 times and it will have 19 regions. By this method, we can iteratively separate an image until the number of regions reach our file size requirement.
  15. \begin{figure}[ht]
  16. \begin{minipage}[b]{0.5\linewidth}
  17. \centering
  18. \includegraphics[width=\linewidth]{figures/real.png}
  19. \caption{PNG image, size = 46KB}
  20. \label{fig:pngImage}
  21. \end{minipage}
  22. \hspace{0.05\linewidth}
  23. \begin{minipage}[b]{0.5\linewidth}
  24. \centering
  25. \includegraphics[width=\linewidth]{figures/separate.png}
  26. \caption{Region separate by CFG}
  27. \label{fig:SeparateImage}
  28. \end{minipage}
  29. \end{figure}
  30. \subsection{Data Structure and Region Selection Algorithm}
  31. To help us choose which region to be separated, we give every region a score, and put them into a heap. For each round, we pick the region with the highest score, separate it into four subregions, calculate the score of subregions, and put them into the heap. We use the sum of square error of pixels in the region $R$ as the score of the region.
  32. \begin{center}
  33. \begin{tabular}{rl}
  34. $\mu = $ & $E(R)$\\
  35. $Score = $ & $\sum\limits_{X\in R} (X-\mu)^2$\\
  36. $= $ & $\sum\limits_{X\in R} X^2 - |R|\mu^2$
  37. \end{tabular}
  38. \end{center}
  39. By the equation shows above, we just need to know the sum of squared and the mean of a region, we can get its score. we can use a segment tree to store all possible regions and its scores. For each node, it store the range on both width and height it covered, sum $\sum\limits_{X\in R} X$, and squared sum $\sum\limits_{X\in R} X^2$ of pixels in the region. By the property of segment tree, tree root start from $0$, and each node $X_i$ has four child $X_{i\times 4+1}$, $X_{i\times 4+2}$, $X_{i\times 4+3}$ and $X_{i\times 4+4}$. Hence, we only need to allocate an large array and recursively process all nodes form root. Algorithm~\ref{code:SegmentTreePreprocess} shows how we generate the tree.
  40. \begin{algorithm*}[h]
  41. \caption{Segment Tree Preprocess}
  42. \label{code:SegmentTreePreprocess}
  43. \begin{algorithmic}[1]
  44. \State $Tree = Array()$
  45. \Function{setTreeNode}{$x, left, right, top, bottom$}
  46. \If {$left = right$ \and $top = bottom$}
  47. \State $Tree[x].Sum = Image[left][top]$
  48. \State $Tree[x].SquareSum = Image[left][top]^2$
  49. \Else
  50. \State $setTreeNode(4x+1, left, (left+right)/2, top, (top+bottom)/2)$
  51. \State $setTreeNode(4x+2, (left+right)/2, right, top, (top+bottom)/2)$
  52. \State $setTreeNode(4x+3, left, (left+right)/2, (top+bottom)/2, bottom)$
  53. \State $setTreeNode(4x+4, (left+right)/2, right, (top+bottom)/2, bottom)$
  54. \State $Tree[x].Sum = \sum\limits_{i = 4x+1}^{4x+4} Tree[i].sum $
  55. \State $Tree[x].SquareSum = \sum\limits_{i = 4x+1}^{4x+4} Tree[i].SquareSum$
  56. \EndIf
  57. \State $Tree[x].SquaredError = Tree[x].SquareSum - \frac{Tree[x].Sum^2}{(right-left+1)\times(bottom-top+1)}$
  58. \EndFunction
  59. \State $setTreeNode(0, 0, Image.Width, 0, Image.Height)$
  60. \end{algorithmic}
  61. \end{algorithm*}
  62. For region selection, we use a priority queue to retrieve the region of considerate regions with highest score. The priority queue start with only root of the segment tree. For each round the priority queue pop the item with highest score and push all its child in to the queue. Algorithm~\ref{code:RegionSelection} shows how we select a region by the priority queue. After the selection finished, we will generate the data string to be sent. The regions in $seperatedRegions$ will be $\beta$ and others in $PriorityQueue$ will be the average value, and then compress the string by Huffman Coding.
  63. \begin{algorithm*}[h]
  64. \caption{Region Selection}
  65. \label{code:RegionSelection}
  66. \begin{algorithmic}[1]
  67. \State $seperatedRegions = Array()$
  68. \State $PriorityQueue = Heap()$
  69. \State $PriorityQueue.Push(Tree[0].SquaredError, 0)$
  70. \For{\State $i = 0..SeperateRounds$}
  71. \State $value, x = PriorityQueue.Pop()$
  72. \State $seperatedRegions.push(x)$
  73. \State $PriorityQueue.Push(Tree[4x+1].SquaredError, 4x+1)$
  74. \State $PriorityQueue.Push(Tree[4x+2].SquaredError, 4x+2)$
  75. \State $PriorityQueue.Push(Tree[4x+3].SquaredError, 4x+3)$
  76. \State $PriorityQueue.Push(Tree[4x+4].SquaredError, 4x+4)$
  77. \EndFor
  78. \end{algorithmic}
  79. \end{algorithm*}
  80. The complexity of our algorithm can be separated into 3 parts. First part is to initialize the segment tree. The size of segment is depends on the size of the image. If the number of pixels is $N$, the height of segment tree is $O(Nlog(N))$, and the number of nodes will be $O(N)$. The time complexity of initialize is $O(N)$. Second part is loading the image. It will need to traverse whole tree from leaf to root. Since segment tree can be store in an array, it also takes $O(N)$ time to load the image. Third part is to separate regions. For each round, we pop an element from heap and push four elements into heap. If we have separated image $K$ times, the size of heap will be $3K+1$. Time complexity of pop and push will be $O(log(K))$, and do it $5K$ times will be $O(Klog(K))$.