Related
i have to code a sudoku ocr for school in C.
I use an edge detection algorithm which returns a bmp file.
However, the returned file only shows 1/3 of the expected output.
Please can someone tell me what is wrong in my code :)
input image (BMP file)
output image (BMP file)
and here's my code :
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <math.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#define MAX_BRIGHTNESS 255
// C99 doesn't define M_PI (GNU-C99 does)
#define M_PI 3.14159265358979323846264338327
/*
* Loading part taken from
* http://www.vbforums.com/showthread.php?t=261522
* BMP info:
* http://en.wikipedia.org/wiki/BMP_file_format
*
* Note: the magic number has been removed from the bmpfile_header_t
* structure since it causes alignment problems
* bmpfile_magic_t should be written/read first
* followed by the
* bmpfile_header_t
* [this avoids compiler-specific alignment pragmas etc.]
*/
typedef struct {
uint8_t magic[2];
} bmpfile_magic_t;
typedef struct {
uint32_t filesz;
uint16_t creator1;
uint16_t creator2;
uint32_t bmp_offset;
} bmpfile_header_t;
typedef struct {
uint32_t header_sz;
int32_t width;
int32_t height;
uint16_t nplanes;
uint16_t bitspp;
uint32_t compress_type;
uint32_t bmp_bytesz;
int32_t hres;
int32_t vres;
uint32_t ncolors;
uint32_t nimpcolors;
} bitmap_info_header_t;
typedef struct {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t nothing;
} rgb_t;
// Use short int instead `unsigned char' so that we can
// store negative values.
typedef short int pixel_t;
pixel_t *load_bmp(const char *filename,
bitmap_info_header_t *bitmapInfoHeader)
{
FILE *filePtr = fopen(filename, "rb");
if (filePtr == NULL) {
perror("fopen()");
return NULL;
}
bmpfile_magic_t mag;
if (fread(&mag, sizeof(bmpfile_magic_t), 1, filePtr) != 1) {
fclose(filePtr);
return NULL;
}
// verify that this is a bmp file by check bitmap id
// warning: dereferencing type-punned pointer will break
// strict-aliasing rules [-Wstrict-aliasing]
if (*((uint16_t*)mag.magic) != 0x4D42) {
fprintf(stderr, "Not a BMP file: magic=%c%c\n",
mag.magic[0], mag.magic[1]);
fclose(filePtr);
return NULL;
}
bmpfile_header_t bitmapFileHeader; // our bitmap file header
// read the bitmap file header
if (fread(&bitmapFileHeader, sizeof(bmpfile_header_t),
1, filePtr) != 1) {
fclose(filePtr);
return NULL;
}
// read the bitmap info header
if (fread(bitmapInfoHeader, sizeof(bitmap_info_header_t),
1, filePtr) != 1) {
fclose(filePtr);
return NULL;
}
if (bitmapInfoHeader->compress_type != 0)
fprintf(stderr, "Warning, compression is not supported.\n");
// move file point to the beginning of bitmap data
if (fseek(filePtr, bitmapFileHeader.bmp_offset, SEEK_SET)) {
fclose(filePtr);
return NULL;
}
// allocate enough memory for the bitmap image data
pixel_t *bitmapImage = malloc(bitmapInfoHeader->bmp_bytesz *
sizeof(pixel_t));
// verify memory allocation
if (bitmapImage == NULL) {
fclose(filePtr);
return NULL;
}
// read in the bitmap image data
size_t pad, count=0;
unsigned char c;
pad = 4*ceil(bitmapInfoHeader->bitspp*bitmapInfoHeader->width/32.) - bitmapInfoHeader->width;
for(size_t i=0; i<bitmapInfoHeader->height; i++){
for(size_t j=0; j<bitmapInfoHeader->width; j++){
if (fread(&c, sizeof(unsigned char), 1, filePtr) != 1) {
fclose(filePtr);
return NULL;
}
bitmapImage[count++] = (pixel_t) c;
}
fseek(filePtr, pad, SEEK_CUR);
}
// If we were using unsigned char as pixel_t, then:
// fread(bitmapImage, 1, bitmapInfoHeader->bmp_bytesz, filePtr);
// close file and return bitmap image data
fclose(filePtr);
return bitmapImage;
}
// Return: true on error.
bool save_bmp(const char *filename, const bitmap_info_header_t *bmp_ih,
const pixel_t *data)
{
FILE* filePtr = fopen(filename, "wb");
if (filePtr == NULL)
return true;
bmpfile_magic_t mag = {{0x42, 0x4d}};
if (fwrite(&mag, sizeof(bmpfile_magic_t), 1, filePtr) != 1) {
fclose(filePtr);
return true;
}
const uint32_t offset = sizeof(bmpfile_magic_t) +
sizeof(bmpfile_header_t) +
sizeof(bitmap_info_header_t) +
((1U << bmp_ih->bitspp) * 4);
const bmpfile_header_t bmp_fh = {
.filesz = offset + bmp_ih->bmp_bytesz,
.creator1 = 0,
.creator2 = 0,
.bmp_offset = offset
};
if (fwrite(&bmp_fh, sizeof(bmpfile_header_t), 1, filePtr) != 1) {
fclose(filePtr);
return true;
}
if (fwrite(bmp_ih, sizeof(bitmap_info_header_t), 1, filePtr) != 1) {
fclose(filePtr);
return true;
}
// Palette
for (size_t i = 0; i < (1U << bmp_ih->bitspp); i++) {
const rgb_t color = {(uint8_t)i, (uint8_t)i, (uint8_t)i};
if (fwrite(&color, sizeof(rgb_t), 1, filePtr) != 1) {
fclose(filePtr);
return true;
}
}
// We use int instead of uchar, so we can't write img
// in 1 call any more.
// fwrite(data, 1, bmp_ih->bmp_bytesz, filePtr);
// Padding: http://en.wikipedia.org/wiki/BMP_file_format#Pixel_storage
size_t pad = 4*ceil(bmp_ih->bitspp*bmp_ih->width/32.) - bmp_ih->width;
unsigned char c;
for(size_t i=0; i < bmp_ih->height; i++) {
for(size_t j=0; j < bmp_ih->width; j++) {
c = (unsigned char) data[j + bmp_ih->width*i];
if (fwrite(&c, sizeof(char), 1, filePtr) != 1) {
fclose(filePtr);
return true;
}
}
c = 0;
for(size_t j=0; j<pad; j++)
if (fwrite(&c, sizeof(char), 1, filePtr) != 1) {
fclose(filePtr);
return true;
}
}
fclose(filePtr);
return false;
}
// if normalize is true, map pixels to range 0..MAX_BRIGHTNESS
void convolution(const pixel_t *in, pixel_t *out, const float *kernel,
const int nx, const int ny, const int kn,
const bool normalize)
{
assert(kn % 2 == 1);
assert(nx > kn && ny > kn);
const int khalf = kn / 2;
float min = FLT_MAX, max = -FLT_MAX;
if (normalize)
for (int m = khalf; m < nx - khalf; m++)
for (int n = khalf; n < ny - khalf; n++) {
float pixel = 0.0;
size_t c = 0;
for (int j = -khalf; j <= khalf; j++)
for (int i = -khalf; i <= khalf; i++) {
pixel += in[(n - j) * nx + m - i] * kernel[c];
c++;
}
if (pixel < min)
min = pixel;
if (pixel > max)
max = pixel;
}
for (int m = khalf; m < nx - khalf; m++)
for (int n = khalf; n < ny - khalf; n++) {
float pixel = 0.0;
size_t c = 0;
for (int j = -khalf; j <= khalf; j++)
for (int i = -khalf; i <= khalf; i++) {
pixel += in[(n - j) * nx + m - i] * kernel[c];
c++;
}
if (normalize)
pixel = MAX_BRIGHTNESS * (pixel - min) / (max - min);
out[n * nx + m] = (pixel_t)pixel;
}
}
/*
* gaussianFilter:
* http://www.songho.ca/dsp/cannyedge/cannyedge.html
* determine size of kernel (odd #)
* 0.0 <= sigma < 0.5 : 3
* 0.5 <= sigma < 1.0 : 5
* 1.0 <= sigma < 1.5 : 7
* 1.5 <= sigma < 2.0 : 9
* 2.0 <= sigma < 2.5 : 11
* 2.5 <= sigma < 3.0 : 13 ...
* kernelSize = 2 * int(2*sigma) + 3;
*/
void gaussian_filter(const pixel_t *in, pixel_t *out,
const int nx, const int ny, const float sigma)
{
const int n = 2 * (int)(2 * sigma) + 3;
const float mean = (float)floor(n / 2.0);
float kernel[n * n]; // variable length array
fprintf(stderr, "gaussian_filter: kernel size %d, sigma=%g\n",
n, sigma);
size_t c = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) {
kernel[c] = exp(-0.5 * (pow((i - mean) / sigma, 2.0) +
pow((j - mean) / sigma, 2.0)))
/ (2 * M_PI * sigma * sigma);
c++;
}
convolution(in, out, kernel, nx, ny, n, true);
}
/*
* Links:
* http://en.wikipedia.org/wiki/Canny_edge_detector
* http://www.tomgibara.com/computer-vision/CannyEdgeDetector.java
* http://fourier.eng.hmc.edu/e161/lectures/canny/node1.html
* http://www.songho.ca/dsp/cannyedge/cannyedge.html
*
* Note: T1 and T2 are lower and upper thresholds.
*/
pixel_t *canny_edge_detection(const pixel_t *in,
const bitmap_info_header_t *bmp_ih,
const int tmin, const int tmax,
const float sigma)
{
const int nx = bmp_ih->width;
const int ny = bmp_ih->height;
pixel_t *G = calloc(nx * ny * sizeof(pixel_t), 1);
pixel_t *after_Gx = calloc(nx * ny * sizeof(pixel_t), 1);
pixel_t *after_Gy = calloc(nx * ny * sizeof(pixel_t), 1);
pixel_t *nms = calloc(nx * ny * sizeof(pixel_t), 1);
pixel_t *out = malloc(bmp_ih->bmp_bytesz * sizeof(pixel_t));
if (G == NULL || after_Gx == NULL || after_Gy == NULL ||
nms == NULL || out == NULL) {
fprintf(stderr, "canny_edge_detection:"
" Failed memory allocation(s).\n");
exit(1);
}
gaussian_filter(in, out, nx, ny, sigma);
const float Gx[] = {-1, 0, 1,
-2, 0, 2,
-1, 0, 1};
convolution(out, after_Gx, Gx, nx, ny, 3, false);
const float Gy[] = { 1, 2, 1,
0, 0, 0,
-1,-2,-1};
convolution(out, after_Gy, Gy, nx, ny, 3, false);
for (int i = 1; i < nx - 1; i++)
for (int j = 1; j < ny - 1; j++) {
const int c = i + nx * j;
// G[c] = abs(after_Gx[c]) + abs(after_Gy[c]);
G[c] = (pixel_t)hypot(after_Gx[c], after_Gy[c]);
}
// Non-maximum suppression, straightforward implementation.
for (int i = 1; i < nx - 1; i++)
for (int j = 1; j < ny - 1; j++) {
const int c = i + nx * j;
const int nn = c - nx;
const int ss = c + nx;
const int ww = c + 1;
const int ee = c - 1;
const int nw = nn + 1;
const int ne = nn - 1;
const int sw = ss + 1;
const int se = ss - 1;
const float dir = (float)(fmod(atan2(after_Gy[c],
after_Gx[c]) + M_PI,
M_PI) / M_PI) * 8;
if (((dir <= 1 || dir > 7) && G[c] > G[ee] &&
G[c] > G[ww]) || // 0 deg
((dir > 1 && dir <= 3) && G[c] > G[nw] &&
G[c] > G[se]) || // 45 deg
((dir > 3 && dir <= 5) && G[c] > G[nn] &&
G[c] > G[ss]) || // 90 deg
((dir > 5 && dir <= 7) && G[c] > G[ne] &&
G[c] > G[sw])) // 135 deg
nms[c] = G[c];
else
nms[c] = 0;
}
// Reuse array
// used as a stack. nx*ny/2 elements should be enough.
int *edges = (int*) after_Gy;
memset(out, 0, sizeof(pixel_t) * nx * ny);
memset(edges, 0, sizeof(pixel_t) * nx * ny);
// Tracing edges with hysteresis . Non-recursive implementation.
size_t c = 1;
for (int j = 1; j < ny - 1; j++)
for (int i = 1; i < nx - 1; i++) {
if (nms[c] >= tmax && out[c] == 0) { // trace edges
out[c] = MAX_BRIGHTNESS;
int nedges = 1;
edges[0] = c;
do {
nedges--;
const int t = edges[nedges];
int nbs[8]; // neighbours
nbs[0] = t - nx; // nn
nbs[1] = t + nx; // ss
nbs[2] = t + 1; // ww
nbs[3] = t - 1; // ee
nbs[4] = nbs[0] + 1; // nw
nbs[5] = nbs[0] - 1; // ne
nbs[6] = nbs[1] + 1; // sw
nbs[7] = nbs[1] - 1; // se
for (int k = 0; k < 8; k++)
if (nms[nbs[k]] >= tmin && out[nbs[k]] == 0) {
out[nbs[k]] = MAX_BRIGHTNESS;
edges[nedges] = nbs[k];
nedges++;
}
} while (nedges > 0);
}
c++;
}
free(after_Gx);
free(after_Gy);
free(G);
free(nms);
return out;
}
int main(const int argc, const char ** const argv)
{
if (argc < 2) {
printf("Usage: %s image.bmp\n", argv[0]);
return 1;
}
static bitmap_info_header_t ih;
const pixel_t *in_bitmap_data = load_bmp(argv[1], &ih);
if (in_bitmap_data == NULL) {
fprintf(stderr, "main: BMP image not loaded.\n");
return 1;
}
printf("Info: %d x %d x %d\n", ih.width, ih.height, ih.bitspp);
const pixel_t *out_bitmap_data =
canny_edge_detection(in_bitmap_data, &ih, 45, 50, 1.0f);
if (out_bitmap_data == NULL) {
fprintf(stderr, "main: failed canny_edge_detection.\n");
return 1;
}
if (save_bmp("out.bmp", &ih, out_bitmap_data)) {
fprintf(stderr, "main: BMP image not saved.\n");
return 1;
}
free((pixel_t*)in_bitmap_data);
free((pixel_t*)out_bitmap_data);
return 0;
}
This isn't really an answer, but I wanted to post the image I obtained from the code.
I took two actions on the .jpg posted a) reduce to 256 colours, b) save as 8-bit .bmp, done with an image editor.
Then after running the code I converted the 8-bit .bmp output to .png to post here.
I only changed one thing for MSVC, the VLA
//float kernel[n * n]; // variable length array
float *kernel = malloc(n * n * sizeof (float));
with free(kernel) at the end of the function. Although there were still several compiler warnings, they didn't seem to be material here, but it's still worth fixing them.
I want to change my color image file to grayscale image file.
I can't use OPENCV and other library.
My code algorithm is like this.
T[3] = {0.299, 0.589, 0.114}
N = size of vertical
M = size of horizontal
for j = 1 ~ N
{
for i = 1 ~ M
Writebuf[i][j] = Readbuf[0][i+M][i] * T[0] + Readbuf[1][i+M][i] * T[1] + Readbuf[2][i+M][i] * T[2]
}
This is my code following algorithm.
#include <stdio.h>
#pragma warning(disable:4996)
int main() {
FILE* fp;
double T[3] = { 0.299, 0.587, 0.114 };
int N = 374;
int M = 374;
int i = 0;
int j = 0;
unsigned char Readbuf[374][374];
unsigned char Writebuf[374][374];
fp = fopen("lena_color.bmp", "rb");
if (fp == NULL)
printf("FIle Read Error");
for (i = 0; i < N; i++)
fread(Readbuf[i], 1, N, fp);
fclose(fp);
for (i = 0; i < N; i++)
{
for (j = 0; j < M; j++)
{
Writebuf[j][i] = Readbuf[0][j + M][i] * T[0] + Readbuf[1][j + M][i] * T[1] + Readbuf[2][j + M][i] * T[2];
}
}
fp = fopen("111.bmp", "wb");
for (i = 0; i < 374; i++);
fwrite(Writebuf[i], 1, 374, fp);
fclose(fp);
return 0;
}
It doesn't save image
Please help me.
I've written a program that resizes a bitmap by a factor between 0-100 (values under 1 shrinks the image). The program works to enlarge files but it doesn't work reducing them.
I think I might be using fseek incorrectly to skip the pixels and rows.
I appreciate any time you commit to reviewing this problem.
Please note the code is ugly because I'm just learning to code. Any recommendations are welcome but may cause additional confusion so please explain your answer to a 5 year old.
You can run the program using a command similar to "./resize .5 large.bmp test.bmp"
Both program files are attached resize.c and bmp.h
I've also attached the before and after images to get a better idea of the problem.
after:
before:
// Copies a BMP file
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "bmp.h"
int zoom(float number, int biwidth);
int main(int argc, char *argv[])
{
// ensure proper usage
if (argc != 4)
{
fprintf(stderr, "Usage: copy infile outfile\n");
return 1;
}
// remember filenames
char* a = NULL;
float num0 = strtof(argv[1], &a);
int num = ceil(num0);
char *infile = argv[2];
char *outfile = argv[3];
if (num0 < 0 || num0 > 100)
{
fprintf(stderr, "Resize only 0-100. Try again.\n");
return 5;
}
// open input file
FILE *inptr = fopen(infile, "rb");
if (inptr == NULL)
{
fprintf(stderr, "Could not open %s.\n", infile);
return 2;
}
// open output file
FILE *outptr = fopen(outfile, "wb");
if (outptr == NULL)
{
fclose(inptr);
fprintf(stderr, "Could not create %s.\n", outfile);
return 3;
}
// read infile's BITMAPFILEHEADER
BITMAPFILEHEADER bf;
fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);
// read infile's BITMAPINFOHEADER
BITMAPINFOHEADER bi;
fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr);
// ensure infile is (likely) a 24-bit uncompressed BMP 4.0
if (bf.bfType != 0x4d42 || bf.bfOffBits != 54 || bi.biSize != 40 ||
bi.biBitCount != 24 || bi.biCompression != 0)
{
fclose(outptr);
fclose(inptr);
fprintf(stderr, "Unsupported file format.\n");
return 4;
}
// calculate old padding
int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
printf("padding%i ", padding);
//create new header files to save to
BITMAPINFOHEADER newbi = bi;
BITMAPFILEHEADER newbf = bf;
//determine width and set minimum size
int biwidth = round(bi.biWidth * num0);
if (biwidth < 3)
{
newbi.biWidth = 3;
}
else
{
newbi.biWidth = biwidth;
}
printf("newbiwidth%i ", newbi.biWidth);
//determine height and set minimum size
int biheight = round(bi.biHeight) * num0;
if (biheight > -3)
{
newbi.biHeight = -3;
}
else
{
newbi.biHeight = biheight;
}
printf("newbiheight%i ", newbi.biHeight);
// determine new padding for scanlines
int newpadding = (4 - (newbi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
printf("newpadding%i ", newpadding);
//determine new image size
newbi.biSizeImage = (newbi.biWidth * sizeof(RGBTRIPLE) + newpadding) * abs(newbi.biHeight);
printf("newbisizeimage%i ", newbi.biSizeImage);
//determine new file size
newbf.bfSize = newbi.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
printf("newbfsize%i ", newbf.bfSize);
// write outfile's BITMAPFILEHEADER
fwrite(&newbf, sizeof(BITMAPFILEHEADER), 1, outptr);
// write outfile's BITMAPINFOHEADER
fwrite(&newbi, sizeof(BITMAPINFOHEADER), 1, outptr);
// temporary storage
int factor = zoom(num0, bi.biWidth);
RGBTRIPLE triple;
RGBTRIPLE *triple1 = malloc(sizeof(RGBTRIPLE) * factor);
RGBTRIPLE *sline = malloc(newbi.biWidth * sizeof(RGBTRIPLE));
//determine whether to loop old or new width
int biheight1 = 0;
int biwidth1= 0;
if ( bi.biWidth > newbi.biWidth)
biwidth1 = newbi.biWidth;
else
biwidth1 = bi.biWidth;
//determine whether to loop old or new height
if ( abs(bi.biHeight) > abs(newbi.biHeight))
biheight1 = abs(newbi.biHeight);
else
biheight1 = abs(bi.biHeight);
// read RGB triple from infile based on shrink or enlarge
for (int i = 0; i < biheight1; i++)
{
printf("H%i ", i);
for (int j = 0; j < biwidth1; j++)
{
printf("W%i ", j);
if (num0 > .5 && num0 < 1)
fread(triple1, sizeof(RGBTRIPLE), factor, inptr);
else
fread(&triple, sizeof(RGBTRIPLE), 1, inptr);
//store new triple as new scanline
for (int m = 0; m < num ; m++)
{
if (num0 <= .5)
{
sline[j] = triple;
}
else if (num0 > .5 && num0 < 1)
{
sline[j] = *triple1;
}
else
{
sline[j * num + m] = triple;
}
printf("T%i,J%i ", m, j);
}
//skip pixel(s) if image is shrinking
for (int n = 0; n < num ; n++)
{
if (num0 > .5 && num0 < 1)
{
fseek(inptr, sizeof(RGBTRIPLE), SEEK_CUR);
}
else if (num0 <= .5)
{
fseek(inptr, (sizeof(RGBTRIPLE) * factor), SEEK_CUR);
}
}
}
// skip over padding, if any
fseek(inptr,padding, SEEK_CUR);
//write new scanline to file
for (int k = 0; k < num; k++)
{
printf("F%i ", k);
fwrite(sline, (newbi.biWidth * 3), 1, outptr);
// add padding if any
for (int h = 0; h < newpadding; h++)
{
fputc(0x00, outptr);
}
}
//skip scanline(s) if shrinking
for (int o = 0; o < num ; o++)
{
if (num0 > .5 && num0 < 1)
{
fseek(inptr, (bi.biWidth + padding), SEEK_CUR);
}
else if (num0 <= .5)
{
fseek(inptr, ((bi.biWidth + padding) * factor), SEEK_CUR);
}
}
}
//free memory
free(sline);
free(triple1);
// close infile
fclose(inptr);
// close outfile
fclose(outptr);
// success
return 0;
}
//determine shrink factor
int zoom(float number, int biwidth)
{
int zoom1;
int a;
int b;
a = (biwidth * number);
b = (biwidth - a);
if ( a > b && b != 0)
{
zoom1 = a/b;
}
else if (a < b && a != 0)
{
zoom1 = b/a;
}
else if (b <= 0)
{
zoom1 = 1;
}
else
{
zoom1 = 1;
}
return zoom1;
}
// BMP-related data types based on Microsoft's own
#include <stdint.h>
// aliases for C/C++ primitive data types
// https://msdn.microsoft.com/en-us/library/cc230309.aspx
typedef uint8_t BYTE;
typedef uint32_t DWORD;
typedef int32_t LONG;
typedef uint16_t WORD;
// information about the type, size, and layout of a file
// https://msdn.microsoft.com/en-us/library/dd183374(v=vs.85).aspx
typedef struct
{
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} __attribute__((__packed__))
BITMAPFILEHEADER;
// information about the dimensions and color format
// https://msdn.microsoft.com/en-us/library/dd183376(v=vs.85).aspx
typedef struct
{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} __attribute__((__packed__))
BITMAPINFOHEADER;
// relative intensities of red, green, and blue
// https://msdn.microsoft.com/en-us/library/dd162939(v=vs.85).aspx
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
The following solution was posted by #CraigEstey:
fseek for skipping scanlines was incomplete. The bi.biWidth needs to be multiplied by the sizeof(RGBTRIPLE)
Use fseek(inptr, ((bi.biWidth * sizeof(RGBTRIPLE) + padding), SEEK_CUR); instead of fseek(inptr, (bi.biWidth + padding), SEEK_CUR);
The program now works for both enlarging and shrinking images with this fix.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <windows.h>
int main()
{
struct rgb { unsigned char r, g, b; };
float scale = 1.5;//0 to 100!
// open input and output file
FILE* inptr = fopen("in.bmp", "rb");
FILE* outptr = fopen("out.bmp","wb");
BITMAPFILEHEADER bf; fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);
BITMAPINFOHEADER bi; fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr);
// calculate old padding
int pad = (4 - (bi.biWidth * 3) % 4) % 4;
//create new header files
BITMAPINFOHEADER bi2 = bi;
BITMAPFILEHEADER bf2 = bf;
//image old
int width = bi.biWidth;
int height = bi.biHeight;
//image new
int width2 = ceil(bi.biWidth * scale);
int height2 = ceil(bi.biHeight *scale);
//new header
bi2.biWidth = width2;
bi2.biHeight = height2;
int pad2 = (4 - (width2 * 3) % 4) % 4;
bi2.biSizeImage = (width2 * 3 + pad2) * height2;
bf2.bfSize = bi2.biSizeImage + 54;
//header save
fwrite(&bf2, sizeof(BITMAPFILEHEADER), 1, outptr);
fwrite(&bi2, sizeof(BITMAPINFOHEADER), 1, outptr);
rgb *p = (rgb*)malloc(width*height* sizeof(rgb)); //image old
rgb *p2 = (rgb*)malloc(width2*height2* sizeof(rgb)); //image2 new
//write p
int say = 0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
fread(p + say, 3, 1, inptr);
say++;
}
fseek(inptr, pad, SEEK_CUR);
}
//write p---->p2
int say2 = 0;
for (int i = 0; i < height2; i++)
{
for (int j = 0; j < width2; j++)
{
int x = j / scale ;
int y = i / scale ;
int say = y * width + x;
memcpy(p2+say2, p + say, sizeof(rgb));
say2++;
}
}
//write file
say = 0;
for (int i = 0; i < height2; i++)
{
for (int j = 0; j < width2; j++)
{
fwrite(p2+say, sizeof(rgb), 1, outptr);
say++;
}
for (int h = 0; h < pad2; h++)
fputc(0x00, outptr);
}
fclose(inptr);
fclose(outptr);
return 0;
}
This is my function to read a matrix from a file. In the text file I have on the first line 2 is n and 3 is m and on the next two lines is the matrix.
I don't have erros, but my program "stop working" and I don't know why. Thank you!
In main I have: readmatrix(n,m,a, "text.txt");
int readmatrix(int* n,int *m, int a[*n][*m], char* filename){
FILE *pf;
int i,j;
pf = fopen (filename, "rt");
if (pf == NULL)
return 0;
fscanf (pf, "%d",n);
for (i=0;i<*n;i++)
{
for(j=0;j<*m;j++)
fscanf (pf, "%d", &a[i][j]);
}
fclose (pf);
return 1;
}
If your compiler supports VLAs or you are using C99, then you can do this:
#include <stdio.h>
int readmatrix(size_t rows, size_t cols, int (*a)[cols], const char* filename)
{
FILE *pf;
pf = fopen (filename, "r");
if (pf == NULL)
return 0;
for(size_t i = 0; i < rows; ++i)
{
for(size_t j = 0; j < cols; ++j)
fscanf(pf, "%d", a[i] + j);
}
fclose (pf);
return 1;
}
int main(void)
{
int matrix[2][3];
readmatrix(2, 3, matrix, "file.dat");
for(size_t i = 0; i < 2; ++i)
{
for(size_t j = 0; j < 3; ++j)
printf("%-3d ", matrix[i][j]);
puts("");
}
return 0;
}
file.dat looks like this:
1 2 3
4 5 6
and the output of my program is
$ ./a
1 2 3
4 5 6
Note that this is a basic example, you should always check the return value of
fscanf. If file.dat had one row only, then you would get in trouble. Also
there are not numbers in the file, you would get also undefined values in the
matrix.
I'd advice to read the whole line with fgets and then parse the line using
sscanf or some other function like strtok, then it would be easier to react
to errors in the input file.
edit
A more robust way of reading a file like this would be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int **readmatrix(size_t *rows, size_t *cols, const char *filename)
{
if(rows == NULL || cols == NULL || filename == NULL)
return NULL;
*rows = 0;
*cols = 0;
FILE *fp = fopen(filename, "r");
if(fp == NULL)
{
fprintf(stderr, "could not open %s: %s\n", filename, strerror(errno));
return NULL;
}
int **matrix = NULL, **tmp;
char line[1024];
while(fgets(line, sizeof line, fp))
{
if(*cols == 0)
{
// determine the size of the columns based on
// the first row
char *scan = line;
int dummy;
int offset = 0;
while(sscanf(scan, "%d%n", &dummy, &offset) == 1)
{
scan += offset;
(*cols)++;
}
}
tmp = realloc(matrix, (*rows + 1) * sizeof *matrix);
if(tmp == NULL)
{
fclose(fp);
return matrix; // return all you've parsed so far
}
matrix = tmp;
matrix[*rows] = calloc(*cols, sizeof *matrix[*rows]);
if(matrix[*rows] == NULL)
{
fclose(fp);
if(*rows == 0) // failed in the first row, free everything
{
fclose(fp);
free(matrix);
return NULL;
}
return matrix; // return all you've parsed so far
}
int offset = 0;
char *scan = line;
for(size_t j = 0; j < *cols; ++j)
{
if(sscanf(scan, "%d%n", matrix[*rows] + j, &offset) == 1)
scan += offset;
else
matrix[*rows][j] = 0; // could not read, set cell to 0
}
// incrementing rows
(*rows)++;
}
fclose(fp);
return matrix;
}
int main(void)
{
size_t cols, rows;
int **matrix = readmatrix(&rows, &cols, "file.dat");
if(matrix == NULL)
{
fprintf(stderr, "could not read matrix\n");
return 1;
}
for(size_t i = 0; i < rows; ++i)
{
for(size_t j = 0; j < cols; ++j)
printf("%-3d ", matrix[i][j]);
puts("");
}
// freeing memory
for(size_t i = 0; i < rows; ++i)
free(matrix[i]);
free(matrix);
return 0;
}
Now file.dat looks like this:
1 2 3 4
4 5 6 5
9 8 8 7
5 5 5 5
1 1 1 1
And the output is
1 2 3 4
4 5 6 5
9 8 8 7
5 5 5 5
1 1 1 1
In this example I calculate the number of columns only for the first column and
use that number for all other columns. If the input file has rows with less
columns that the first row, then the missing values are stored with 0. If it has rows with
more columns than the row will be trimmed.
I calculate the number of rows like this:
while(sscanf(scan, "%d%n", &dummy, &offset) == 1)
{
scan += offset;
(*cols)++;
}
First I declare a pointer scan to point to line, so that I can modify the
pointer without losing the original line. The %n in sscanf is not counted in
the number of successfull conversions, this returns the position of scan where
it stopped reading. I used that to loop the sscanf. I explicitly check that
sscanf returns 1 and if that's the case, I increment the number of columns and
I update scan to update to the point where sscanf stoppped reading. This
allows me to continue scanning until the end of the line is reached. I use a
similar technique to parse all the integers.
If you're not afraid of using goto, an easy-to-read, robust way to read a matrix looks like this:
typedef struct Matrix
{
size_t width, height;
double **data;
} Matrix;
Matrix read_matrix(char const *filename)
{
Matrix matrix;
FILE *file;
if ((file = fopen(filename, "rt")) == NULL)
goto error;
if (fscanf(file, "%zu %zu", &matrix.width, &matrix.height) != 2)
goto error_file;
if ((matrix.data = (double **)calloc(matrix.height, sizeof(double *))) == NULL)
goto error_file;
for (size_t y = 0; y < matrix.height; ++y)
if ((matrix.data[y] = (double *)malloc(matrix.width * sizeof(double))) == NULL)
goto error_matrix;
for (size_t y = 0; y < matrix.height; ++y)
for (size_t x = 0; x < matrix.width; ++x)
if (fscanf(file, "%lf", &matrix.data[y][x]) != 1)
goto error_matrix;
fclose(file);
return matrix;
error_matrix:
for (size_t y = 0; y < matrix.height; ++y)
free(matrix.data[y]);
free(matrix.data);
error_file:
fclose(file);
error:
return (Matrix){0, 0, NULL};
}
I have an array called puzzle which consist of words/letters/random strings and I want to check if it has any of the same strings in another array called dictionary (the strings in dictionary are listed in alphabetical order)
So I believe my problem is the binary search in my program, I'm not entire sure how to work around it using strings. I tried to use some strcmp() but I don't think thats the way to go?
When the program runs, it gets no output. that there is no matches but there are.
here is my binary search function:
int binsearch(char **dictionary, char *puzzle) {
int start = 1; //excluded first string of dictionary array bc #
int end = listlength;
while (start < end) {
int mid = (start + end) / 2;
int temp = strcmp(dictionary[mid], puzzle);
if (temp < 0) {
start = mid + 1; //it is in upper half
} else
if (temp > 0) { //check lower half
end = mid;
} else
return 1; //found a match hopefully
}
return 0;
}
and my entire code is here if maybe something you need to see
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define listlength 149256
#define maxWordLen 19
char **getWords(int rows, int cols);
void freeArray(char **array, int rows);
char **makeGridArray(int rows, int cols);
int binsearch(char **dictionary, char *puzzle);
void wordSearch(char **dictionary, char **puzzle, int row, int col);
const int DX_SIZE = 8;
const int DX[] = { -1, -1, -1, 0, 0, 1, 1, 1 };
const int DY[] = { -1, 0, 1, -1, 1, -1, 0, 1 };
int main() {
//read in dictionary
int i, j, x = 0, numCases, gridRow, gridCol;
char **words = getWords(listlength, maxWordLen);
//Get number of cases.
printf("enter number of cases:\n");
scanf("%d", &numCases);
//process each case.
while (x < numCases) {
scanf("%d%d", &gridRow, &gridCol);
//make word search grid
char **grid = makeGridArray(gridRow + 1, gridCol);
/* for testing if grid is storing properly
for (i = 0; i < gridRow + 1; i++) {
printf("%s\n", grid[i]);
}
*/
printf("Words Found Grid #%d:\n", x + 1);
wordSearch(words, grid, gridRow + 1, gridCol);
x++;
freeArray(grid, gridRow + 1);
}
freeArray(words, listlength);
}
char **getWords(int rows, int cols) {
int i;
//allocate top level of pointers.
char **words = malloc(sizeof(char*) * rows);
//allocate each individual array
for (i = 0; i < rows; i++) {
words[i] = malloc(sizeof(char) * cols + 1);
}
//read dictionary.txt
FILE *dictionary = fopen("dictionary.txt", "r");
for (i = 0; i < rows; i++) {
fgets(words[i], cols + 1,dictionary);
}
fclose(dictionary);
return words;
}
char **makeGridArray(int rows, int cols) {
//allocate top level of pointers.
char **grid = malloc(sizeof(char*) * rows);
int i, j;
//allocate each individual array
for (i = 0; i < rows; i++) {
grid[i] = malloc(sizeof(char) * cols + 1);
}
//read in user input grid
for (i = 0; i < rows; i++) {
gets(grid[i]);
}
return grid;
}
int binsearch(char **dictionary, char *puzzle) {
int start = 1; //excluded first string of dictionary array bc #
int end = listlength;
while (start < end) {
int mid = (start + end) / 2;
int temp = strcmp(dictionary[mid], puzzle);
if (temp < 0) {
start = mid + 1; //it is in upper half
} else
if (temp > 0) { //check lower half
end = mid;
} else
return 1; //found a match hopefully
}
return 0;
}
void wordSearch(char **dictionary, char **puzzle, int row, int col) {
int i, X, Y, dir;
char wordsfound[19] = { '\0' };
for (X = 0; X < row + 1; X++) {
for (Y = 0; Y < col; Y++) {
for (dir = 0; dir < DX_SIZE; dir++) //check every direction
for (i = 0; i < 19; i++) {
//will continue in direction DX,DY starting at x,y
int nextX = X + DX[dir] * i;
int nextY = Y + DY[dir] * i;
if (nextX < 0 || nextX >= row) break; //keep in bounds
if (nextY < 0 || nextY >= col) break;
//store the string of letters to check
wordsfound[i] = (puzzle[nextX][nextY]);
if (i > 3) { //minimum word is 4
wordsfound[i + 1] = '\0';
//if the string of letters is actually a word, print
int bin = binsearch(dictionary, wordsfound);
if (bin) {
printf("%s\n", wordsfound);
}
}
}
}
}
return;
}
void freeArray(char **array, int rows) {
//free arrays
int i;
for (i = 0; i < rows; i++) {
free(array[i]);
}
free(array);
}
The problem is in the getwords() function: you read the words from the dictionary with fgets() but forget to remove the trailing \n. All words in the dictionary have a trailing \n, so none of them match your searches.
Here is a corrected version:
char **getWords(int rows, int cols) {
char line[256];
int i;
//allocate top level of pointers.
char **words = malloc(sizeof(char*) * rows);
//read dictionary.txt
FILE *dictionary = fopen("dictionary.txt", "r");
for (i = 0; i < rows; i++) {
if (!fgets(line, sizeof line, dictionary))
line[0] = '\0';
line[strcspn(line, "\n")] = '\0';
words[i] = strdup(line);
}
fclose(dictionary);
return words;
}
Note that it would be better not to rely on a known magical listlength. You could also ignore comment and empty lines while reading the dictionary.