Here are several things that may help you improve your code.
Isolate platform-specific code
If you must have stdafx.h, consider wrapping it so that the code is portable:
#ifdef WINDOWS
#include "stdafx.h"
#endif
In this case, with only a single file, there's no advantage to having it, so I'd recommend simply deleting that line.
Eliminate spurious typedef
The code currently contains this:
typedef struct point {
int x_coordinate, y_coordinate;
};
However, in C++, the typedef is not needed since a struct definition creates a new type. Simply omit the word typedef here.
Use objects
Almost all of the functions in the code operate on a single global variable named image_array. This strongly suggests an object instead in which the image_array is a class and most of the functions are member functions instead of standalone C-style functions.
Use a switch instead of long if ...else chain
The command procesing is much easier to see and understand if a switch statement is used instead of the long if...else chain. The default case can then be used for unrecognized commands. On my machine, this also makes the code slightly faster.
Use the appropriate data type
The description of the problem says that a color is a single character, but it's defined as a std::string in most of the code. It seems to me that a more appropriate choice would be to define a Color type and use that. I'd probably do this:
using Color = char;
However, if there's some reason you must use a std::string for this, you could use this:
using Color = std::string;
The advantage here is that it is easy to understand the intended usage if the functions are declared using syntax like this:
void add_matching_neighbours(point p, Color original_color, Color new_color, vector<point> &points_queue);
Eliminate unused variables
Unused variables are a sign of poor code quality, so eliminating them should be a priority. In this code, final_color gets set but is never actually used. My compiler also tells me that. Your compiler is probably also smart enough to tell you that, if you ask it to do so.
Choose easier names
The point struct is quite simple, but the names for the coordinates are x_coordinate and y_coordinate. While those are fine, descriptive names, I think they're overly long. I'd be inclined to simply name them x and y instead and save a lot of typing and shorten some really long lines that are currently within the code.
Use for instead of while where appropriate
Within the color_box function is this code:
int x = x1;
int y = y1;
while (x != x2 + x_adjustment) {
while (y != y2 + y_adjustment) {
color_pixel(x, y, color);
y += y_adjustment;
}
x += x_adjustment;
y = y1;
}
This can be much simplified and also easier to understand by using a for loop instead of while:
for (int x = x1; x != x2 + x_adjustment; x += x_adjustment) {
for (int y = y1; y != y2 + y_adjustment; y += y_adjustment) {
color_pixel(x, y, color);
}
}
Name useful constants
In the existing code, the value "0" is used multiple times to represent the color "white". I'd recommend formalizing that equivalence by naming the constants.
static const Color white{'0'};
In this case, I've defined it as a single char per my previous suggestion.
Think carefully about memory allocation
The code for initialise_array contains theres three lines:
for (int i = 0; i < width+ 1; i++) {
image_array.push_back(vector<Color>());
}
The creates each column as an empty vector, forcing the vector to resize (probably more than once) as items are added to the vector. Since we already know the size, we can eliminate a lot of reallocations by initializing the std::vector to the known correct size as we create it:
for (int i = 0; i < width+ 1; i++) {
image_array.push_back(vector<Color>(height+1));
}
Even better, we do the same thing to the outer vector and pass in an initialized vector:
image_array.reserve(width+1);
for (int i = 0; i < width+ 1; i++) {
image_array.push_back(vector<Color>(height+1, white));
}
Perform bounds checking
If we construct an image that is 64x32 using I 64 32 then attempt to create a filled box with the command L 65 20 +, the x dimension of 65 is out of bounds. Unfortunately, the program doesn't seem to notice that and attempts to use the out of bounds and crashes.
Omit return 0
When a C or C++ program reaches the end of main the compiler will automatically generate code to return 0, so there is no need to put return 0; explicitly at the end of main.
Note: when I make this suggestion, it's almost invariably followed by one of two kinds of comments: "I didn't know that." or "That's bad advice!" My rationale is that it's safe and useful to rely on compiler behavior explicitly supported by the standard. For C, since C99; see ISO/IEC 9899:1999 section 5.1.2.2.3:
[...] a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument; reaching the } that terminates the main function returns a value of 0.
For C++, since the first standard in 1998; see ISO/IEC 14882:1998 section 3.6.1:
If control reaches the end of main without encountering a return statement, the effect is that of executing return 0;
All versions of both standards since then (C99 and C++98) have maintained the same idea. We rely on automatically generated member functions in C++, and few people write explicit return; statements at the end of a void function. Reasons against omitting seem to boil down to "it looks weird". If, like me, you're curious about the rationale for the change to the C standard read this question. Also note that in the early 1990s this was considered "sloppy practice" because it was undefined behavior (although widely supported) at the time.
So I advocate omitting it; others disagree (often vehemently!) In any case, if you encounter code that omits it, you'll know that it's explicitly supported by the standard and you'll know what it means.