* imageops.c - Simple operations on images
*
* C laboratory exercises.
* Richard Vaughan, 2014.
*/
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
/*-------------------------------------------------
PART 0: DEMONSTRATION
*/
// get the value in the array at coordinate (x,y)
uint8_t get_pixel( const uint8_t array[],
unsigned int cols,
unsigned int rows,
unsigned int x,
unsigned int y )
{
assert( x < cols );
assert( y < rows );
return array[ y*cols + x ];
}
// set the pixel at coordinate {x,y} to the specified color
void set_pixel( uint8_t array[],
unsigned int cols,
unsigned int rows,
unsigned int x,
unsigned int y,
uint8_t color )
{
assert( x < cols );
assert( y < rows );
array[ y * cols + x ] = color;
}
// Set every pixel to 0 (black)
void zero( uint8_t array[],
unsigned int cols,
unsigned int rows )
{
// your code here.
}
// Returns a pointer to a freshly allocated array that contains the
// same values as the original array, or a null pointer if the
// allocation fails. The caller is responsible for freeing the array
// later.
uint8_t* copy( const uint8_t array[],
unsigned int cols,
unsigned int rows )
{
// your code here
/*uint8_t* cp = malloc(cols*rows*sizeof(uint8_t)); //creates new array
if(cp ==NULL) return NULL;
for(int i =0; i<rows; y++){
for(int x =0; i<cols; x++){
}
}*/
return NULL;
}
/*-------------------------------------------------
PART 1: OPERATIONS ON THE WHOLE IMAGE
*/
/* TASK 1 - three easy functions to get started */
// Return the darkest color that appears in the array; i.e. the
// smallest value
uint8_t min( const uint8_t array[],
unsigned int cols,
unsigned int rows )
{
int dark = array[0];
for(int i=1; i<cols*rows; i++){
if(array[i]<dark){
dark = array[i];
}
}
return dark;
}
// Return the lightest color that appears in the array; i.e. the
// largest value
uint8_t max( const uint8_t array[],
unsigned int cols,
unsigned int rows )
{
int light = array[0];
for(int i =1; i<cols*rows; i++){
if(array[i]> light){
light = array[i];
}
}
return light;
}
// TASK 2
// Replace every instance of pre_color with post_color.
void replace_color( uint8_t array[],
unsigned int cols,
unsigned int rows,
uint8_t pre_color,
uint8_t post_color )
{
for(int i=0; i<cols*rows; i++){
if(array[i] == pre_color){
array[i] = post_color;
}
}
}
/* TASK 3 - two functions */
// flip the image, left-to-right, like in a mirror.
void flip_horizontal( uint8_t array[],
unsigned int cols,
unsigned int rows )
{
int start, end, temp;
for(int i=0; i<rows; i++){
start = i*cols;
end = (cols-1)+i*cols;
while(start<end){
temp= array[start];
array[start] = array[end];
array[end] = temp;
start++;
end--;
}
}
}
// flip the image top-to-bottom.
void flip_vertical( uint8_t array[],
unsigned int cols,
unsigned int rows )
{
int start1, start2, temp;
int startrow = 0, endrow= rows-1;
while(startrow<endrow){
start1=startrow*cols;
start2=endrow*cols;
for(int i =0; i<cols; i++){
temp = array[start1];
array[start1] = array[start2];
array[start2] = temp;
start1++;
start2++;
}
startrow++;
endrow--;
}
}
/* TASK 4 */
// Find the first coordinate of the first pixel with a value that
// equals color. Search from left-to-right, top-to-bottom. If it is
// found, store the coordinates in *x and *y and return 1. If it is
// not found, return 0.
int locate_color( const uint8_t array[],
unsigned int cols,
unsigned int rows,
uint8_t color,
unsigned int *x,
unsigned int *y )
{
int found =0, index;
for(unsigned int yy =0; yy<rows; yy++){
for(unsigned int xx=0; xx<cols;xx++){
index = xx + yy*cols;
if( array[index] == color ){
*x = xx;
*y = yy;
found = 1;
break;
}
}
if( found == 1 ){
break;
}
}
return found;
}
/* TASK 5 */
// Invert the image, so that black becomes white and vice versa, and
// light shades of grey become the corresponding dark shade.
void invert( uint8_t array[],
unsigned int cols,
unsigned int rows )
{
uint8_t greyscale[256];
int color = 255;
// create an array with numbers 0 to 255:
for(int i =0; i< 256; i++){
greyscale[i] = color;
color--;
}
// inverts the image:
for(int k=0; k<cols*rows; k++){
array[k] = greyscale[array[k]];
}
}
/* TASK 6 */
// Multiply every pixel by scale_factor, in order to brighten or
// darken the image. Any resulting value over 255 is
// thresholded to 255.
void scale_brightness( uint8_t array[],
unsigned int cols,
unsigned int rows,
double scale_factor )
{
for(int i=0; i<cols*rows; i++){
double k= round((double) array[i] * scale_factor);
if(k <= 255){
array[i] = (uint8_t) k;
}else{
array[i] = 255;
}
}
}
/* TASK 7 */
// Normalize the dynamic range of the image, i.e. Shift and scale the
// pixel colors so that that darkest pixel is 0 and the lightest pixel
// is 255. Hint: you already wrote min() and max().
void normalize( uint8_t array[],
unsigned int cols,
unsigned int rows )
{
uint8_t darkest = min(array, cols, rows);
uint8_t lightest = max(array, cols, rows);
uint8_t arr[lightest-darkest+1];
double scale_factor = (round) (256/(max-min+1));
for(int i=darkest; i<lightest-darkest+1; i++){
arr[i] = i;
}
for(int i=0; i<cols*rows; i++){
for(uint8_t k=0; k<lightest-darkest+1; i++){
if(arr[k] == array[i]){
double new = k*scale_factor;
array[i] = (uint8_t) new;
break;
}
}
}
}
/* TASK 8 */
// Return a new image of size rows/2 by cols/2 If the original image
// has an odd number of columns, ignore its rightmost column. If the
// original image has an odd number of rows, ignore its bottom row.
// The value of a pixel at (p,q) in the new image is the average of
// the four pixels at (2p,2q), (2p+1,2q), (2p+1,2q+1), (2p,2q+1) in
// the original image.
uint8_t* half( const uint8_t array[],
unsigned int cols,
unsigned int rows )
{
// creates a new array
unsigned int newCols, newRows;
if(cols %2 != 0 ){
newCols = cols-1;
} else if(rows%2 != 0){
newRows = rows-1;
}
newCols = newCols/2;
newRows = newRows/2;
uint8_t* arr= malloc(newCols*newRows*sizeof(uint8_t));
// changes values of each element
for(int y=0; y<newRows; y++){
for(int x =0; x<newCols; x++){
// creates an average of four pixels
uint8_t p22q = array[2*x+2*y*cols];
uint8_t p21_2q = array[(2*x+1)+2*y*cols];
uint8_t p21_2q1 = array[(2*x+1)+(2*y+1)*cols];
uint8_t p2_2q1 = array[(2*x)+(2*y+1)*cols];
double avg = round((p22q+p21_2q1+p21_2q+p2_2q1)/4);
arr[x+y*cols]= (uint8_t)avg;
}
}
return arr;
}
/*-------------------------------------------------
PART 2: OPERATIONS ON IMAGE SUB-REGIONS
These functions operate only on a rectangular region of the array
defined by a (left,top) corner (i.e. closer to the image origin) and
(right,bottom) corner (i.e. further from the image origin).
The region includes all the columns from [left, right-1] inclusive,
and allthe rows from [top, bottom-1] inclusive.
In every case, you may assume that left <= right and top <= bottom:
do not need to test for this.
The area of the region is right-left * bottom-top pixels, which
implies that if left == right or top == bottom, the region has no
area and is defined as "empty". Each function notes how to handle
empty regions.
In every function, use assert() to test bounds on the region
corners.
*/
/* TASK 9 */
// Set every pixel in the region to color. If the region is empty, the
// image must be unchanged.
void region_set( uint8_t array[],
unsigned int cols,
unsigned int rows,
unsigned int left,
unsigned int top,
unsigned int right,
unsigned int bottom,
uint8_t color )
{
for(int y=0; y<rows; y++){
if( y == bottom ){
break;
}
if( (y >= top) && (y < bottom)){
for(int x=0; x<cols; x++){
if( (x >= left) && (x < right)){
array[(x+y*cols)] = color;
}
}
}
}
}
/* TASK 10 */
// Return the sum of all the pixels in the region. Notice the large
// return type to handle potentially large numbers. Empty regions
// return the sum 0.
unsigned long int region_integrate( const uint8_t array[],
unsigned int cols,
unsigned int rows,
unsigned int left,
unsigned int top,
unsigned int right,
unsigned int bottom )
{
unsigned long int sum = 0;
for( int y=0; y<rows; y++){
if(y == bottom){
break;
}
if( (y>= top) && (y<bottom) ){
for(int x=0; x<cols; x++){
if( (x >= left) && (x< right)){
sum = sum + array[(x+y*cols)];
}
}
}
}
return sum;
}
/* TASK 11 */
// Get a new image which is a copy of the region. Empty regions return
// a null pointer. If memory allocation fails, return a null
// pointer. The caller is responsible for freeing the returned array
// later.
uint8_t* region_copy( const uint8_t array[],
unsigned int cols,
unsigned int rows,
unsigned int left,
unsigned int top,
unsigned int right,
unsigned int bottom )
{
uint8_t*arr = malloc(cols*rows*sizeof(uint8_t));
int i =0;
if (arr == 0){
return NULL;
}
if ((left == right) || (top == bottom)){
return NULL;
}
for( int y=0; y<rows; y++){
if(y == bottom){
break;
}
if( (y>= top) && (y<bottom) ){
for(int x=0; x<cols; x++){
if( (x >= left) && (x< right)){
arr[i] = array[x+y*cols];
i++;
}
}
}
}
return arr;
}
No comments:
Post a Comment