Channels ▼
RSS

Security

Visual Cryptography and Bit-Plane Complexity Segmentation

Source Code Accompanies This Article. Download It Now.


The Implementation

To illustrate this model, I wrote an application using Python, the Python Imaging Library (PIL) (www.pythonware.com/products/pil/), and the numarray package for Python (www.stsci.edu/resources/software_hardware/numarray). PIL adds image-processing capabilities to Python and processes a range of image formats. numarray lets Python efficiently manipulate large numeric arrays, similar to Matlab, IDL, or Octave.

There is a common convention in processing binary (black-and-white) images: If any black pixel in the image is denoted by 1 and any white pixel is 0, you can "transform" any binary black-and-white image into a binary matrix. This is the approach used in my application.

In the embedding process, you select 858 squares from a larger matrix (a share in the model) and write back 9x9 squares into some other matrix (normally a bit-plane); see Listings One and Two, respectively. The algorithm to calculate the complexity of a region in a bit-plane can be implemented as in Listing Three.

def square(matrix, n, d):
  # returns a square slice of dim d from a matrix
  # n - square number
  maxX = len(matrix[0])
  maxY = len(matrix[:,0])
  xsquares = maxX/d
  ysquares = maxY/d
  dy, dx = divmod(n, xsquares)
  xslc = dx * d
  yslc = dy * d
  return matrix[xslc:xslc+d, yslc:yslc+d]
Listing One

def writesquare(matrix, square, n):
  # writes a square of dim d into a bigger matrix
  # n - square number
  # returns the matrix with the overwritten sqaure
  maxX = len(matrix[0])
  maxY = len(matrix[:,0])
  sqX = len(square[0])
  sqY = len(square[:,0])
  xsquares = maxX/sqX
  ysquares = maxY/sqY
  dy, dx = divmod(n, xsquares)
  xslc = dx * sqX
  yslc = dy * sqY
  matrix[xslc:xslc+sqX, yslc:yslc+sqY] = square
  return matrix
Listing Two

def complexity(matrix):
  maxX = len(matrix[0])
  maxY = len(matrix[:,0])
  norm = maxX*maxY
  cmp = 0.
  first = matrix[0][0]
  for x in range(maxX):
    for y in range(maxY):
        if first != matrix[x][y]:
            cmp += 1
            first = matrix[x][y]
  if cmp != 0:
      cmp /= norm
  
  return cmp
Listing Three

To ensure the "blind" character of the embedding scheme, you have to provide additional information (like sequence number and the flag for the conjugated areas) to any 8x8 square read from a share. The additional information is written back into the vessel, together with the 8x8 square of embedding data. The required space is obtained by bordering the square with one row and one column. Though generally defined, the functions in Listings Four(a) and (b) can perform the bordering as well.

(a)
def insert_line(where, line, matrix):
        maxX = len(matrix[0])
        maxY = len(matrix[:,0])+1
        if len(line) != maxX:
            print "[ERR] Unable to append line."
            sys.exit(1)
        getback = zeros((maxY, maxX))
        for y in range(maxY):
            if y == where:
                getback[y] = line
            else:
                if y < where:
                    getback[y] = matrix[y]
                else:
                    getback[y] = matrix[y-1]
        return getback

(b)
def insert_column(where, column, matrix):
        tmatrix = transpose(matrix)
        tcolumn = transpose(column)
        tmpback = insert_line(where, tcolumn[0], tmatrix)
        return transpose(tmpback)
Listing Four

The program also provides other tools for tasks such as generating a random binary matrix or checkerboard pattern, initializing log files, defining some standard directories, and the like. All these are implemented in a utils package.

The application has compression, embedding, and extraction modules. All components work on 8-bit gray-level or 24-bit true-color images. I focus on the 8-bit images because the processing of the true-color images only involves this extension: PIL lets you switch between different pixel representations of an image using the convert function. In terms of converted images, there are only two accepted formats: L (8-bit grayscale) and/or RGB (24-bit true color). This lets you convert input images in RGB format like this:


try:
  image = __original_image.convert("RGB")
except IOError:
  print "Cannot convert image: "      + image_name

After a successful conversion, the image object is in RGB format. For such objects, PIL offers a method that returns a tuple containing the individual image components ("bands" in the PIL documentation). This means you can say:


red, green, blue = image.split()

The red, green, blue objects this time are 8-bit grayscale images. All three modules of the application are implemented in a separate class called image.

Compression, which is based on BPCS, only determines image regions with a complexity above a determined threshold. These regions are overwritten with white color. The embedding module uses the modified BPCS scheme. The module performs the bordering of the 8x8 initial square, correspondingly inserting the sequence numbers and the "conjugated flag" if needed (see Listing Six, available at www.ddj.com/code/).

The function starts with a given sequence number and returns the last sequence number it used. This is because of the embedding scenario itself: During the process, you have to move from one bit-plane to another, and, in the case of true-color images, from one color component to another. So the function has to "know" what the current sequence number is and return the sequence number it finished with for the next iteration.

The extraction module checks the complexity of any region in the image and searches for embedded data. The application also tries to determine if the complete chain of sequence numbers was extracted; if not, it reports the missing squares.

As in Table 1, the only 2x2 matrices that should exist in a share are the diagonal ones. The extraction module also uses an error-detecting mechanism and informs you if some region of the image was altered—a "wrong" 2x2 matrix was found. As the embedding function, the extraction function starts with an initial sequence number and returns the next sequence number when finished (see Listing Seven, available at www.ddj.com/code/).


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video