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//----------------------------------------------
58bool 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//----------------------------------------------
67double 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//----------------------------------------------
98void 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//----------------------------------------------
109QImage* 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
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//==============================================
QImage * blackWhiteEffect(QString filename, ManipulationOptions *options)
int width
Definition blur.cpp:79
int height
Definition blur.cpp:79
double computeLocalGrayVal(QImage *image, int x, int y)
void pickRandomPixelWithinBlock(int width, int height, int blockX, int blockY, int BLOCK_SIZE, int &x, int &y)
bool pixelValid(QImage *image, int x, int y)
void drawDotAt(QImage *image, int x, int y, int)
QImage * pointillismEffect(QString filename, ManipulationOptions *)
QImage * editedImage