AlbumShaper  1.0a3
pointillism.cpp
Go to the documentation of this file.
1 //==============================================
2 // copyright : (C) 2003-2005 by Will Stokes
3 //==============================================
4 // This program is free software; you can redistribute it
5 // and/or modify it under the terms of the GNU General
6 // Public License as published by the Free Software
7 // Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //==============================================
10 
11 //Systemwide includes
12 #include <qimage.h>
13 #include <qstring.h>
14 #include <cstdlib>
15 #include <time.h>
16 
17 //Projectwide includes
18 #include "pointillism.h"
19 #include "blackWhite.h"
20 #include "manipulationOptions.h"
21 
22 //----------------------------------------------
23 // Inputs:
24 // -------
25 // QString filename - location of original image on disk
26 // StatusWidget* status - widget for making progress visible to user
27 //
28 // Outputs:
29 // --------
30 // QImage* returned - constructed image
31 //
32 // Description:
33 // ------------
34 // This method constructs an image using a pointillism approach using luminance
35 // data from the original image.
36 //
37 // This effect is under heavy development and will be documented
38 // in full when it is complete.
39 //----------------------------------------------
40 
41 //==============================================
43  int blockX, int blockY,
44  int BLOCK_SIZE,
45  int &x, int &y )
46 {
47  int dx = rand() % BLOCK_SIZE;
48  int dy = rand() % BLOCK_SIZE;
49  x = blockX*BLOCK_SIZE + dx;
50  y = blockY*BLOCK_SIZE + dy;
51 
52  if(x < 0) x = 0;
53  if(y < 0) y = 0;
54  if(x >= width ) x = width-1;
55  if(y >= height) y = height-1;
56 }
57 //----------------------------------------------
58 bool pixelValid( QImage* image, int x, int y )
59 {
60  return (
61  x >= 0 &&
62  y >= 0 &&
63  x < image->width() &&
64  x < image->height() );
65 }
66 //----------------------------------------------
67 double computeLocalGrayVal( QImage* image, int x, int y )
68 {
69  int weights[3][3] = { {1,2,1}, {2,4,2}, {1,2,1} };
70 
71  int divisorSum = 0;
72  double sum = 0;
73  int xp, yp;
74  for(yp = QMAX( y-1, 0); yp < QMIN( image->height()-1, y+1 ); yp++)
75  {
76  uchar* scanLine = image->scanLine(yp);
77 
78  for(xp = QMAX( x-1, 0); xp< QMIN( image->width()-1, x+1 ); xp++)
79  {
80  //compute dx and dy values
81  int dx = xp - x;
82  int dy = yp - y;
83 
84  //compute weight index
85  int weightX = dx+1;
86  int weightY = dy+1;
87 
88  //update sum and divisor count
89  sum+= (weights[weightX][weightY] * qGray( *((QRgb*)scanLine+xp) ) );
90  divisorSum+= weights[weightX][weightY];
91  }
92  }
93 
94  //return weighted average
95  return sum/divisorSum;
96 }
97 //----------------------------------------------
98 void drawDotAt( QImage* image, int x, int y, int )
99 {
100  //TODO: antialias over grid, for now
101  //just update this pixel value
102  uchar* scanLine = image->scanLine(y);
103  QRgb* rgb = ((QRgb*)scanLine+x);
104  int red = qRed(*rgb);
105  red = (int) (0.6*red);
106  *rgb = qRgb( red, red, red);
107 }
108 //----------------------------------------------
109 QImage* pointillismEffect( QString filename, ManipulationOptions* )
110 {
111  //intialize seed using current time
112  srand( unsigned(time(NULL)) );
113 
114  //load original image and convert to grayscale
115  QImage* originalImage = blackWhiteEffect( filename, NULL );
116 
117  //construct edited image
118  QImage* editedImage = new QImage( originalImage->width(),
119  originalImage->height(),
120  originalImage->depth() );
121 
122  //fill with white since we'll be drawing black/color dots on top
123  editedImage->fill( qRgb(255,255,255) );
124 
125  //break image into BLOCK_SIZE x BLOCK_SIZE blocks. iterate over
126  //each block and pick a random pixel within. Local
127  //average gray value in edited image is > originalImage + thresh
128  //then draw a dot at pixel. continue doing this for each block
129  //and repeat until ???
130  const int BLOCK_SIZE = 8;
131 
132  //compute image size in blocks
133  int blocksWide = editedImage->width() / BLOCK_SIZE;
134  if(blocksWide*BLOCK_SIZE < editedImage->width())
135  { blocksWide++; }
136 
137  int blocksTall = editedImage->height() / BLOCK_SIZE;
138  if(blocksTall*BLOCK_SIZE < editedImage->height())
139  { blocksTall++; }
140 
141  //iterate over image say 100 times, we'll need to fix this outer loop to be smarter?
142  int bx,by,x,y;
143  for(int i=0; i<10; i++)
144  {
145  //iterate over all blocks
146  for(bx=0; bx<blocksWide; bx++)
147  {
148  for(by=0; by<blocksTall; by++)
149  {
150  //pick random pixel within block
151  pickRandomPixelWithinBlock( editedImage->width(),
152  editedImage->height(),
153  bx, by,
154  BLOCK_SIZE,
155  x, y );
156 
157  double curGrayVal = computeLocalGrayVal( editedImage, x, y );
158  double goalGrayVal = computeLocalGrayVal( originalImage, x, y );
159 
160  //too bright -> draw dot
161  if( curGrayVal > goalGrayVal )
162  { drawDotAt( editedImage, x, y, 5 ); }
163  }
164  }
165  }
166 
167  //free grayscale form of original image
168  delete originalImage;
169  originalImage = NULL;
170 
171  //return pointer to edited image
172  return editedImage;
173 }
174 //==============================================
bool pixelValid(QImage *image, int x, int y)
Definition: pointillism.cpp:58
double computeLocalGrayVal(QImage *image, int x, int y)
Definition: pointillism.cpp:67
int width
Definition: blur.cpp:79
void drawDotAt(QImage *image, int x, int y, int)
Definition: pointillism.cpp:98
QImage * editedImage
QImage * pointillismEffect(QString filename, ManipulationOptions *)
QImage * blackWhiteEffect(QString filename, ManipulationOptions *options)
Definition: blackWhite.cpp:60
void pickRandomPixelWithinBlock(int width, int height, int blockX, int blockY, int BLOCK_SIZE, int &x, int &y)
Definition: pointillism.cpp:42
int height
Definition: blur.cpp:79