reading a UPC barcode from an image - c

i need some guidance on how to get a 12 digit barcode from a bmp file, i'm completely clueless on how approach this.
i started by reading the image into a bitmam, how can i continue?
example: the barcode of the image below is 081034489030.
how to i get these numbers?
void part1() {
int width, height;
unsigned char ** img = NULL;
img = readBMP("package.bmp", &height, &width);
}
unsigned char** readBMP(char* filename, int* height_r, int* width_r)
{
int i, j;
FILE* f;
fopen_s(&f,filename, "rb");
unsigned char info[54];
fread(info, sizeof(unsigned char), 54, f); // read the 54-byte header
// extract image height and width
//from header
int width = *(int*)&info[18];
int height = *(int*)&info[22];
int pad_needed = 4 - (3 * width) % 4; // pad calculation
int paddedRow = 3 * width + ((pad_needed != 4) ? pad_needed : 0);
unsigned char** map2d = (unsigned char**)malloc(width * sizeof(unsigned
char*)); // alocate memory for img 2d array
for (i = 0; i < width; i++) {
map2d[i] = (unsigned char*)malloc(height * sizeof(unsigned char));
}
unsigned char* data = (unsigned char*)malloc(paddedRow * sizeof(unsigned
char)); // allocate memory for each read from file
for (i = 0; i < height; i++) {
fread(data, sizeof(unsigned char), paddedRow, f); //read line from file
for (j = 0; j < width; j++) {
map2d[j][i] = (int)data[3 * j]; // insert data to map2d. jump 3,
//becasue we need only one value of the colors (RGB)
}
}
free(data);
fclose(f);
*width_r = width;
*height_r = height;
return map2d;
}

You need to apply computer vision techniques to:
Segment the barcode from the image
Decode the barcode information so that it can be further used in an application.
There is no single answer to this problem, and it will definitely not be a one-liner.
A way to start is by using a dedicated computer vision library like OpenCV. It will not only handle the image loading on your behalf, but enable you to apply advanced image processing algorithms on the loaded data. It supports C, Python, C#, so you should easily find the version that matches your language of choice.
Once OpenCV is added to your project, it is time to solve point number 1. A good algorithm to start from is described Detecting Barcodes in Images with Python and OpenCV. Don't get distracted by the use of Python, the same OpenCV functions are available in C as well, the idea is to understand the algorithm.
Assuming you now have a working segmentation algorithm, the last step is to decode the barcode itself. Here I would suggest Parts 2 and 3 of this article as a starting point. There are also pre-built libraries (if you Google, there are plenty of UPC decoders written in Java or C# like this one), so with a bit of digging you may be able to find an out-of-the-box solution.
Hope this helps.

Related

Compression Ratio Calculation in Delta Encoding

I am new to use Delta encoding to compress Hex data, I used the C implementation in wiki, so if my data is like 0xFFFFFFF,0xFFFFFFF,0xFFFFFFF,0xFFFFFFF,0xFFFFFFF the encoding result will be as follows : 0xFFFFFFF,0x0000000,0x0000000,0x0000000,0x0000000 , unlike rest of lossless algorithms which compression ratio = origial size / compressed size , i found that size of data will be fixed like before the compression, so how could i calculate compression ratio in delta encoding ? and how could i compress redundant delta ?
The code is :
{
unsigned char last = 0;
for (int i = 0; i < length; i++)
{
unsigned char current = buffer[i];
buffer[i] = current - last;
last = current;
}
}
void delta_decode(unsigned char *buffer, int length)
{
unsigned char last = 0;
for (int i = 0; i < length; i++)
{
unsigned char delta = buffer[i];
buffer[i] = delta + last;
last = buffer[i];
}
} ```
Delta encoding is a step before compression that does not, itself, compress. It enables the subsequent compression. You should then take the result of delta encoding and feed it to a standard lossless compressor to see how much it compresses.
Your question in the comments "but will Huffman or RLE work with Hex data in numeric format?" suggests some confusion on your part. The result of the delta encoding is the contents of the array in binary. Not the hexadecimal and text representation of that binary data.

Scaling down a BMP image in C

int main(void) {
setvbuf( stdout, NULL, _IONBF, 0 );
//Input File
FILE* infile;
infile = fopen("test.bmp", "rb");
//Vars for image
char bm[2];
int imageSize;
int fileSize;
int width, height;
char restOfDataOne[12];
char restOfDataTwo[28];
//Read Header Info
fread(bm, 1, 2, infile);
fread(&fileSize, 1, 4, infile);
imageSize = fileSize - 54;
fread(restOfDataOne, 1, 12, infile);
fread(&width, sizeof(int), 1, infile);
fread(&height, sizeof(int), 1, infile);
fread(restOfDataTwo, 1, 28, infile);
int rowWidth = width * 3;
//Read Image Data
unsigned char image[height][(width * 3)];
fread(image, sizeof(char), imageSize, infile);
//Close
fclose(infile);
//#################################################
//Small BMP
//#################################################
FILE* smallOut;
smallOut = fopen("small.bmp", "wb");
//Small Vars
int imageSizeSmall = imageSize / 4;
int fileSizeSmall = imageSizeSmall + 54;
int widthSmall = width / 2;
int heightSmall = height / 2;
int smallRowWidth = widthSmall * 3;
unsigned char imageSmall[heightSmall][smallRowWidth];
//Image Data
int c, d, e;
//For every 4 pixels.. store one in small image
for(c = 0; c < rowWidth; c++) {
for(d = 0; d < height; d++) {
//imageSmall[d/2][c/2] = image[d][c];
for(e = 0; e < 3; e++) {
//grab every 1 out of 4 and place into small?
}
}
}
So I have the following code which reads the bmp image, then I need to scale it down and output it to the smaller version which is half the width and half the height, therefore being 4 times smaller in all. So I know I have to grab 1 out of every 3 pixels? and put it into my new smallImage, but I have tried multiple things with nested for loops and just can't get the algorithm down. I have viewed multiple posts here on stackexchange but people are using libraries, which I cannot use. (Homework). I'm not looking for someone to do it for me, just looking for someone to point me in the right direction or give me a hint?
Full code here.
https://pastebin.com/ZVmXtmCx
You have a nice and detailed study for your problem at the following address:
http://www.davdata.nl/math/bmresize.html
I quote:
This is done by scanning these pixels, left to right, top to bottom
while projecting the destination pixel over the source bitmap.

Simple reverb alghoritm when buffer is small

I'm trying to implement simple delay/reverb described in this post https://stackoverflow.com/a/5319085/1562784 and I have a problem. On windows where I record 16bit/16khz samples and get 8k samples per recording callback call, it works fine. But on linux I get much smaller chunks from soundcard. Something around 150 samples. Because of that I modified delay/reverb code to buffer samples:
#define REVERB_BUFFER_LEN 8000
static void reverb( int16_t* Buffer, int N)
{
int i;
float decay = 0.5f;
static int16_t sampleBuffer[REVERB_BUFFER_LEN] = {0};
//Make room at the end of buffer to append new samples
for (i = 0; i < REVERB_BUFFER_LEN - N; i++)
sampleBuffer[ i ] = sampleBuffer[ i + N ] ;
//copy new chunk of audio samples at the end of buffer
for (i = 0; i < N; i++)
sampleBuffer[REVERB_BUFFER_LEN - N + i ] = Buffer[ i ] ;
//perform effect
for (i = 0; i < REVERB_BUFFER_LEN - 1600; i++)
{
sampleBuffer[i + 1600] += (int16_t)((float)sampleBuffer[i] * decay);
}
//copy output sample
for (i = 0; i < N; i++)
Buffer[ i ] = sampleBuffer[REVERB_BUFFER_LEN - N + i ];
}
This results in white noise on output, so clearly I'm doing something wrong.
On linux, I record in 16bit/16khz, same like on Windows and I'm running linux in VMWare.
Thank you!
Update:
As indicated in answered post, I was 'reverbing' old samples over and over again. Simple 'if' sovled a problem:
for (i = 0; i < REVERB_BUFFER_LEN - 1600; i++)
{
if((i + 1600) >= REVERB_BUFFER_LEN - N)
sampleBuffer[i + 1600] += (int16_t)((float)sampleBuffer[i] * decay);
}
Your loop that performs the actual reverb effect will be performed multiple times on the same samples, on different calls to the function. This is because you save old samples in the buffer, but you perform the reverb on all samples each time. This will likely cause them to overflow at some point.
You should only perform the reverb on the new samples, not on ones which have already been modified. I would also recommend checking for overflow and clipping to the min/max values instead of wrapping in that case.
A probably better way to perform reverb, which will work for any input buffer size, is to maintain a circular buffer of size REVERB_SAMPLES (1600 in your case), which contains the last samples.
void reverb( int16_t* buf, int len) {
static int16_t reverb_buf[REVERB_SAMPLES] = {0};
static int reverb_pos = 0;
for (int i=0; i<len; i++) {
int16_t new_value = buf[i] + reverb_buf[reverb_pos] * decay;
reverb_buf[reverb_pos] = new_value;
buf[i] = new_value;
reverb_pos = (reverb_pos + 1) % REVERB_SAMPLES;
}
}

Weird results when implementing Sobel Filter [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I have been learning about computer vision and wanted to implement some simple techniques in C. For the first technique, I am doing the Sobel edge detection filter. I understand how it works and so I thought it should be fairly easy to code, but I am getting very weird results.
I am using the following image:
and getting this as a result
New Results!:
It should be noted that I am using the .ppm image format (the links are to jpgs since I could not find an image host that supports .ppm)
Anyways, here is the section of my code that implements Sobel:
/**********************************************************
This program takes in an image file and applies the Sobel
Filter edge detection technique to it.
**********************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "ppmReader.h"
void sobelFilter(){
//Sobel kernels dx (horizontal) and dy (vertical)
int horizFilter[3][3] = {{ 1, 0, -1},
{ 2, 0, -2},
{ 1, 0, -1}};
int vertFilter[3][3] = {{ 1, 2, 1},
{ 0, 0, 0},
{-1, -2, -1}};
int pixVal = 0;
int horizPixVal = 0;
int vertPixVal = 0;
int x, y, i, j;
//Quick check to make sure dimensions are correct
printf("Using a Width of: %d\n", width);
printf("Using a Height of: %d\n\n", height);
//Start filtering process here
for(x = 0; x < width; x++){
for(y = 0; y < height; y++){
pixVal = 0;
horizPixVal = 0;
vertPixVal = 0;
if(!((x == 0) || (x == width-1) || (y == 0) || (y == height-1))){ //If the current pixel is along the border, ignore it and set to zero
for(i = -1; i <= 1; i++){ //because the kernel does not align to it
for(j = -1; j <= 1; j++){
horizPixVal += (int)(image[y + j][x + i][0]) * horizFilter[i + 1][j + 1]; //Only need to focus on one of the RGB values since the output is
vertPixVal += (int)(image[y + j][x + i][0]) * vertFilter[i + 1][j + 1]; //greyscale and all three values are the same
}
}
}
pixVal = sqrt((horizPixVal * horizPixVal) + (vertPixVal * vertPixVal)); //Calculate magnitude
pixVal = sqrt(horizPixVal * horizPixVal);
if(pixVal > 255) pixVal = 255; //Clamp value within 8-bit range
filteredImage[y][x][0] = (unsigned char)pixVal;
}
}
}
Here is the code that reads the .ppm file:
unsigned char image[MAX_IMAGE_HEIGHT][MAX_IMAGE_WIDTH][3];
unsigned char filteredImage[MAX_IMAGE_HEIGHT][MAX_IMAGE_WIDTH][3];
void readPPMImageData(){
char fileName[MAX_NAME];
char imageBuff[MAX_BUFF];
width = 0;
height = 0;
maxColor = 0;
int x;
int y;
FILE* file;
printf("------------------------------------------------------------\n");
printf("Now attempting to read in the .ppm image file data...\n");
printf("------------------------------------------------------------\n\n");
printf("What is the image file name (*.ppm)? : ");
scanf("%s", fileName);
file = fopen(fileName, "rb"); //open the file specified by the user in binary read mode
if(file == NULL){ //but if the file was not found, terminate program
printf("\nThe file %s could not be found! Terminating program...\n", fileName);
exit(1);
}
//The first step is to read in the file type and check it agains P6 (file type of .ppm images)
fgets(imageBuff, MAX_BUFF, file);
if(imageBuff[0] != 'P' || imageBuff[1] != '6'){
printf("\nInvalid image type! Acceptable type is: %s --- Received type is: %c%c\n\n", "P6", imageBuff[0], imageBuff[1]);
}
printf("Magic Number is: %c%c\n", imageBuff[0], imageBuff[1]);
while(width == 0 || height == 0){
fgets(imageBuff, MAX_BUFF, file);
if(imageBuff[0] != '#') {
sscanf(imageBuff, "%d %d", &width, &height);
}
}
printf("Width is: %d\n", width);
printf("Height is: %d\n", height);
//if(feof(file)){
//
//}
while(maxColor == 0){
fgets(imageBuff, MAX_BUFF, file);
if(imageBuff[0] != '#') {
sscanf(imageBuff, "%d", &maxColor);
}
}
printf("Maximum color value is: %d\n", maxColor);
for(x = 0; x < width; x++){
for(y = 0; y < height; y++){
image[y][x][0] = (unsigned char)fgetc(file); //Get Red value
image[y][x][1] = (unsigned char)fgetc(file); //Get Green value
image[y][x][2] = (unsigned char)fgetc(file); //Get Blue value
}
}
printf("Finished reading image data!\n\n");
fclose(file);
}
And here is the code that creates the new .ppm file after filtering:
void createPPMImage(){
char fileName[MAX_NAME];
FILE* file;
int x;
int y;
printf("------------------------------------------------------------\n");
printf("Now attempting to create new .ppm image file...\n");
printf("------------------------------------------------------------\n\n");
printf("What is the name of the output image file (*.ppm)? : ");
scanf("%s", fileName);
printf("Width is: %d\n", width);
printf("Height is: %d\n", height);
printf("Maximum color value is: %d\n", maxColor);
file = fopen(fileName, "wb");
fputs("P6\n", file);
fprintf(file, "%d %d\n", width, height);
fprintf(file, "%d\n", maxColor);
for(x = 0; x < width; x++){
for(y = 0; y < height; y++){
fputc(filteredImage[y][x][0], file); //Write Red value
fputc(filteredImage[y][x][0], file); //Write Green value
fputc(filteredImage[y][x][0], file); //Write Blue value
}
}
printf("Finished creating new filtered image!\n\n");
fclose(file);
}
I'm 100% sure the issue isn't with the reading or writing of the image as I tested those functions without the filter applied and only get issues once I use the above function.
Any help is appreciated because as far as I can see, the indexing/formula seems to be correctly implemented but that is obviously not true.
EDIT: As Dave and others have pointed out, I am no longer 100% sure that the error is within the Sobel function and it appears this is just some indexing mistake I have made when using the .ppm format. I went ahead and posted the code for my .ppm reader/writer functions and the new results I am getting after applying the [y][x][color] scheme propsed by anatolyg below. I am sorry if my post is way too long and if it is please let me know as this is my first post and I am not entirely sure what is proper yet.
Images are usually indexed with y coordinate first and x second, like this:
... image[y + j][x + i] ...
This is a convention that keeps people from getting confused when dealing with images in C. Unfortunately, it kinda contradicts the one that Matlab uses, so I just hope you are doing it all in C.
In addition, PPM format specification says that the red/green/blue values are interleaved, so the "colour plane" must be the last index:
... image[y + j][x + i][0] ...
unless there was some reordering of the input file while loading it into memory. You didn't show code that reads from the file, so it's hard to know whether it did any reordering.
Addition: reading and writing the file should follow raster ordering, that is, finish pixels of one line before proceeding to next line:
for(y = 0; y < height; y++){
for(x = 0; x < width; x++){
...
}
}
It is also recommended to do processing in this manner; this is not an absolute must, but it will reduce confusion, and might make your processing faster in addition (by using CPU cache more effectively).

Mono to Stereo conversion

I have the following issue here: I get a block of bytes (uint16_t*) representing audio data, and the device generating them is capturing mono sound, so obviously I have mono audio data, on 1 channel. I need to pass this data to another device, which is expecting interleaved stereo data (so, 2 channels). What I want to do is basically duplicate the 1 channel in data so that both channels of the stereo data will contain the same bytes. Can you point me to an efficient algorithm doing this?
Thanks,
f.
If you just want interleaved stereo samples then you could use a function like this:
void interleave(const uint16_t * in_L, // mono input buffer (left channel)
const uint16_t * in_R, // mono input buffer (right channel)
uint16_t * out, // stereo output buffer
const size_t num_samples) // number of samples
{
for (size_t i = 0; i < num_samples; ++i)
{
out[i * 2] = in_L[i];
out[i * 2 + 1] = in_R[i];
}
}
To generate stereo from a single mono buffer then you would just pass the same pointer for in_L and in_R, e.g.
interleave(mono_buffer, mono_buffer, stereo_buffer, num_samples);
You might want to do the conversion in-place to save some memory. Depends on how small an amount of memory the device in question has. So you might want to use something like this instead of Paul R's approach:
void interleave(uint16_t buf[], const int len)
{
for (int i = len / 2 - 1, j = len - 1; i >= 0; --i) {
buf[j--] = buf[i];
buf[j--] = buf[i];
}
}
When getting the sound data from the mono device, you allocate a buffer that's twice as big as needed and pass that to the mono device. This will fill half the buffer with mono audio. You then pass that buffer to the above function, which converts it to stereo. And finally you pass the buffer to the stereo device. You save an extra allocation and thus use 33% less memory for the conversion.
Pass to both channels the same pointer? If that violates restrict rules, use memcpy()?
Sorry, but your question is otherwise to broad. API? OS? CPUArchitectures?
You are going to have to copy the buffer and duplicate it. As you haven't told us the format, how it is terminated, I can't give code, but it will look like a simple for loop.
int_16* allocateInterleaved(int_16* data, int length)
int i;
int *copy = malloc(sizeof(int_16)*length*2);
if(copy == NULL) {
/* handle error */
}
for(i =0; i<length; i++) {
copy[2*i] = data[i];
copy[2*i+1] = data[i];
}
return copy;
}
forgive any glaring typos, my C is a bit rusty. typdef in whatever type you need for signed 16bit into int_16. Don't forget to free the copy buffer, or better yet reuse it.
You need to interleave the data, but if the frame length is anything greater than one, none of the above solutions will work. The below code can account for variable frame lengths.
void Interleave(BYTE* left, BYTE* right, BYTE* stereo,int numSamples_in, int frameSize)
{
int writeIndex = 0;
for (size_t j = 0; j < numSamples_in; j++)
{
for (int k = 0; k < frameSize; k++)
{
int index = j * frameSize + k;
stereo[k + writeIndex] = left[index];
stereo[k + writeIndex + frameSize] = right[index];
}
writeIndex += 2 * frameSize;
}
}

Resources