Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bit planes of a 1-plane image in OpenCV only work for 1/3 of the image

I'm trying to learn OpenCV by doing a few things on my own. In this particular case, I wanted to take the bit planes of a grayscale image. The code seems to have worked, but it only works well for the bit 7 and 6, not so much for the remaining 6, as it only shows a good result for about 1/3 of the image. I just haven't found what's wrong with it as of yet. I'd greatly appreciate some help on the matter, as I'm just doing my first codes with the libraries.

Here's what I get for the first bit:

enter image description here

And here is it for the 7th bit:

enter image description here

And here's my code:

#include <opencv2\opencv.hpp>
#include <math.h>

using namespace cv;
using namespace std;

int main( int argc, char** argv ) {
   Mat m1 = imread("grayscalerose.jpg");
   imshow("Original",m1);
   int cols, rows, x, y;
   cols = m1.cols;
   rows = m1.rows;
   printf("%d %d \n",m1.rows,m1.cols);
   Mat out1(rows, cols, CV_8UC1, Scalar(0));
   out1 = (m1/128); //Here's where I divide by either 1,2,4,8,16,32,64, or 128 to get the corresponding bit planes

   for (int y = 0; y < rows; y++){
        for (int x = 0; x < cols; x++){
            out1.at<uchar>(y,x) = (out1.at<uchar>(y,x) % 2);
   } }

   out1 = out1*255;
   imshow("out1",out1);
   waitKey(0);
   destroyWindow( "out1" );

}

Thanks in advance. I hope my explanation wasn't too messy.

like image 809
D. Sanz Avatar asked Apr 04 '16 17:04

D. Sanz


People also ask

What is bit planes of an image?

A bit plane of a digital discrete signal (such as image or sound) is a set of bits corresponding to a given bit position in each of the binary numbers representing the signal.

What is bit plane encoding?

Bit-plane encoding is intended for use aboard spacecraft. The technique presumes input data in binary form. The encoder implemen- tation consists of a memory to store datasamples, a monitor, and a code box. Both the monitor and the code box perform simple opera- tions on binary sequences.

What is bit plane slicing and how it is implemented?

Bit plane slicing is a method of representing an image with one or more bits of the byte used for each pixel. One can use only MSB to represent the pixel, which reduces the original gray level to a binary image. The three main goals of bit plane slicing is: Converting a gray level image to a binary image.

Which bit plane contains the most information?

The highest bit-plane is the Most Significant Bit (MSB) and the lowest bit-plane is the Least Significant Bit (LSB). As such, each bit-plane descending from MSB to LSB makes a decaying, marginal contribution to the overall information contained in the image.


1 Answers

First let's read the image in as grayscale only. (As mentioned by user3896254).

Then, let's prepare a mask image, where only the least significant bit is set -- i.e. all the values are 1.

Then the algorithm is simple. Let's avoid per-pixel manipulation (the two nested for loops), and try to take advantage of the optimized operations provided by OpenCV.

For each bit (0..7):

  • Mask out the lowest order bit in the work image.
  • Scale the masked image by 255 to make it black/white.
  • Store the output.
  • Divide values in work image by 2 -- i.e. shift all bits by 1 position to the right.

Code:

#include <opencv2\opencv.hpp>
#include <cstdint>

int main(int argc, char** argv)
{
    cv::Mat input_img(cv::imread("peppers.png", 0));

    int32_t rows(input_img.rows), cols(input_img.cols);

    cv::Mat bit_mask(cv::Mat::ones(rows, cols, CV_8UC1));

    cv::Mat work_img(input_img.clone());
    std::string file_name("peppers_bit0.png");
    for (uint32_t i(0); i < 8; ++i) {
        cv::Mat out;
        cv::bitwise_and(work_img, bit_mask, out);

        out *= 255;
        cv::imwrite(file_name, out);

        work_img = work_img / 2;
        file_name[11] += 1;
    }
}

We can develop even shorter (and probably faster) version using a single matrix expression.

We can calculate the appropriate divisor using the expression (1<<i). We divide every element by this value to shift the bits, mask each element by ANDing it with 1, and then scale all the elements by 255:

#include <opencv2\opencv.hpp>
#include <cstdint>

int main(int argc, char** argv)
{
    cv::Mat input_img(cv::imread("peppers.png", 0));

    std::string file_name("peppers_bit0.png");
    for (uint32_t i(0); i < 8; ++i) {
        cv::Mat out(((input_img / (1<<i)) & 1) * 255);
        cv::imwrite(file_name, out);

        file_name[11] += 1;
    }
}

Sample run

Input image:

Bit 0:

Bit 1:

Bit 2:

Bit 3:

Bit 4:

Bit 5:

Bit 6:

Bit 7:

like image 62
Dan Mašek Avatar answered Sep 28 '22 08:09

Dan Mašek